Writing JavaScript That Still Works Without jQuery

jQuery is still the most comfortable way to write a lot of day‑to‑day front‑end code. It smooths over browser differences, gives us convenient selectors, and makes events feel less painful than the older DOM APIs.
But it is worth knowing where jQuery is doing essential work and where it has simply become muscle memory.
For small behaviours, writing plain JavaScript can make a page lighter, reduce dependency on a library, and make the code easier to move between projects. The trick is not to replace every jQuery call for the sake of it. The trick is to recognise the cases where the browser already gives us enough.
Keep the Behaviour Small and Specific
Plain JavaScript is a good fit when the behaviour is modest:
- toggling a class
- reading a data attribute
- attaching a click handler
- finding a nearby element
- enabling a small progressive enhancement
It is less attractive when the code needs heavy animation, old browser normalisation, plugin ecosystems, or complex AJAX behaviour. In those cases, jQuery may still be the sensible tool.
The question is not "can this be done without jQuery?" Most things can. The better question is "will this be clearer, safer, and easier to support without jQuery?"
Select Elements Carefully
The most obvious replacement for $() is querySelector or querySelectorAll.
That gives you CSS‑style selectors in the browser, but it does not behave exactly like jQuery. querySelector returns the first matching element or null. It does not give you an empty jQuery object that can silently accept chained calls.
That means code should check the result before using it. The article on why `querySelector` returns `null` covers the basic failure mode. It is usually caused by running code before the element exists, using the wrong selector, or expecting a page to contain markup that appears only on another template.
The plain JavaScript version can be more explicit:
- find the element
- stop if it is not present
- attach the behaviour
That is slightly more verbose than jQuery, but it makes the dependency visible.
Use classList for Class Changes
For class manipulation, classList is often much clearer than editing className strings by hand.
It lets you add, remove, toggle, and check classes without writing fragile string replacement code. The article on `classList` in JavaScript goes into the API in more detail.
This is a good example of a place where plain JavaScript has become pleasant enough for everyday use. If the target browsers support it, adding jQuery only to toggle a class is hard to justify.
Treat Events as a Browser Feature, Not a jQuery Feature
Modern browsers support addEventListener, which is the native equivalent you will reach for most often.
jQuery's event system still helps with browser normalisation and convenience, especially on older projects, but for newer browsers the native event object is often enough. The most important habit is the same either way: do not attach events before the DOM is ready, and do not assume every template contains every element.
If the behaviour is added to a list that may change, event delegation can still be useful. That is not a jQuery‑only idea. Listen on a stable parent and inspect the event target.
The related article on `closest()` in vanilla JavaScript and jQuery is useful here because many delegated handlers need to walk up from a clicked child to the real component element.
Read Data Attributes Directly
Small components often need configuration from the markup: an ID, a URL, a label, or a boolean flag. jQuery's .data() API is convenient, but plain JavaScript can read data‑* attributes through dataset.
Do not overuse data attributes as a replacement for proper configuration. They are best for small pieces of component‑level information that belong with the rendered markup.
Keep Fallbacks Boring
Writing without jQuery is not automatically progressive enhancement. It can be just as fragile as jQuery if the markup depends entirely on script.
The fallback checks are the same:
- links should still point somewhere useful
- forms should still submit
- hidden content should not become permanently hidden
- script errors in one enhancement should not stop everything else
Plain JavaScript makes dependencies a little more visible, but it does not remove the need for careful HTML.
That is why feature detection in front‑end development sits so close to this topic. The practical question is rarely "can this browser run JavaScript?" It is whether this page has the specific feature, element, and state the script is about to use.
Wrapping Up
Writing JavaScript without jQuery is not about proving a point. It is about choosing the smallest useful tool for the behaviour in front of you.
jQuery remains valuable where it reduces real browser pain or where an existing project already depends on it. For small enhancements, though, the browser APIs are often enough. Use them carefully, check for missing elements, and keep the HTML useful before any script runs.
Key Takeaways
- Do not replace jQuery automatically. Replace it where plain JavaScript is clearer and well supported.
querySelector,classList,addEventListener,closest, anddatasetcover many small behaviours.- Native DOM APIs can fail more loudly than jQuery, so check for missing elements.
- Progressive enhancement still matters whether the code uses jQuery or plain JavaScript.
- The best result is smaller code that still behaves sensibly when scripts fail.
Postscript
This article is part of an archive restored from a previous version of my website on 27 May 2026. The original publication date is accurate. The article has since been restored and lightly edited for formatting, imagery, broken links, and current internal references.