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")
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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!'); })
Enter fullscreen mode Exit fullscreen mode

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

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

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); });
Enter fullscreen mode Exit fullscreen mode

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);
      })
    })
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

As it happens, this is easier in native JS:

    let form = ev.target.closest('form');
Enter fullscreen mode Exit fullscreen mode

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') {
Enter fullscreen mode Exit fullscreen mode

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') {
Enter fullscreen mode Exit fullscreen mode

And a bonus:

    bonus.classList.replace('old', 'new');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And for the vanilla:

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

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

    el.dataset.thing = 'wibble';
    el.dataset['thing'] = 'wibble';
Enter fullscreen mode Exit fullscreen mode

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 !