DEV Community

Curtis Maloney
Curtis Maloney

Posted on • Edited on

How I stopped using jQuery and learned to love the API

I recently read in an article that something like 75% of sites still use jQuery. I don't know how accurate this stat is, but it surprised me none the less that someone would think it was that high.

Now, I'm not going to start ranting about how everyone should be using React, Vue, $THIS_MONTHS_HOT_FRAMEWORK - I'm more often a vanilla JavaScript person - but I think it's important to recognise why jQuery was created, and why it's not so relevant any more.

jQuery began in the wild old days, when standards were loose, competition was questionable, and compatibility was low. Also, the DOM and other browser APIs were far less developed - not to mention JavaScript itself.

It brought us the simple $() interface, for selecting and working on collections of elements easily. It abstracted over cross-browser compatibility issues. It encapsulated common patterns, saving us the tedium of repeating that code.

Vanilla

So what follows will be some common jQuery snippets and patterns, and how to implement them in plain vanilla JS. If you want to keep on using jQuery, well, that's up to you - it still has value, legacy projects deserve consistency, and I'm not here to decide your tools for you.

Selecting

Clearly, the most common act is to select elements.

    var buttons = $("button.myclass")

In the DOM we now have querySelector and querySelectorAll. The first for selecting the first match, the latter for all matches. This can be called on the document, or any element.

    let buttons = document.querySelectorAll('button.myclass')

This returns a NodeList, which is like an Array, but not quite. Importantly, you can subscript it like an array, and it has forEach.

Event listeners

To attach an event listener to a selection of elements, in jQuery you would:

    buttons.on('click', function (ev) { alert('You clicked it!'); })

In vanilla JS this is a little more verbose, using addEventListener:

    buttons.forEach(
      el => el.addEventListener('click', ev => alert('You clicked it!'))
    )

Additionally, jQuery allows you to add "delegated" handlers, which bind to an element and catch events from its descendants that match a pattern.

    $('div.toolbar').on('click', '.hide', function (ev) { doHideToolbar(ev.target); });

For vanilla JS, this again requires a little more work, but far less than it used need:

    document.querySelectorAll('div.toolbar').forEach(el => {
      el.addEventListener('click', ev => {
        if (!ev.target.matches('.hide')) return;
        doHideToolbar(ev.target);
      })
    })

So here we add an event listener to each of our dev.toolbar elements to catch "click" events, and then filter based on the delegate selector using the matches method.

Climbing the tree

Often times you'll want to walk back up the DOM to a specific node.

    var form = $(ev.target).closest('form');

As it happens, this is easier in native JS:

    let form = ev.target.closest('form');

Manipulating classes

Another common action is dealing with classes on elements; Adding or removing, toggling or testing.

    var button = $('button[type=submit]').first();

    button.addClass('active');
    button.removeClass('active');
    button.toggleClass('active');

    if button.hasClass('active') {

In the modern DOM, Elements have a classList attribute, which affords us even more power:

    let button = document.querySelector('button[type=submit]');

    button.classList.add('active');
    button.classList.remove('active');
    button.classList.toggle('active');

    if button.classList.contains('active') {

And a bonus:

    bonus.classList.replace('old', 'new');

The classList, which is a DOMTokenList, also supports many Array-like interfaces, like forEach(), and length.

Attributes and Data

In the dark old days, manipulating attributes on DOM elements was a minefield of incompatible methods and byzantine restrictions. So, of course, jQuery abstracted it.

It's worth noting, however, that there is a clear distinction in jQuery between 'attributes' and 'properties' - that is, between attributes of the DOM element, and properties of the HTML document.

    var inp = $('input[type=checkbox]');

    inp.prop('value')
    inp.prop('value', 'six');

Again, modern DOMs provide attributes, as a NamedNodeMap: an unordered, live map of names to Attr instances.

    let inp = document.querySelector('input[type=checkbox]')

    inp.attributes.value;
    // alternatively
    inp.attributes['value'];

    inp.attributes.value = 'six';

Further, jQuery provides the data() method for manipulating data-* attributes on elements. And once again, modern DOM brings us Element.dataset, which is a DOMStringMap.

    $('[data-thing]').data('thing')  // yields the value of data-thing
    $('[data-thing]').data('thing', 'wibble')  // sets the value

And for the vanilla:

    let el = document.querySelector('[data-thing]')

    el.dataset.thing
    el.dataset['thing']

    el.dataset.thing = 'wibble';
    el.dataset['thing'] = 'wibble';

Finally

A great resource shown to me by someone I asked to review this article is http://youmightnotneedjquery.com/ which includes examples of jQuery and how to replace it for IE8+/9+/10+.

More?

I was going to dive into $.ajax and family, but I feel this post is long enough, and that would be equally as long, so I'll save it for another post.

If you have more you'd like to see, just comment and I'll help where I can.

Top comments (3)

Collapse
 
katlum3 profile image
Katlum

Love this post! Just calling out that:

let button = document.querySelector('button[type=submit']);

Has a little mistake. The "]" is outside the string.

let button = document.querySelector('button[type=submit]');

Should fix it :3

Collapse
 
funkybob profile image
Curtis Maloney

Thanks!

It's a typo I make all too often :)

Collapse
 
alphons profile image
Alphons van der Heijden

good primer !