How I stopped using jQuery and learned to love the API
Tags: javascript
Published: 2019-04-23 04:09:07

---
title: How I stopped using jQuery and learned to love the API
published: true
description: jQuery, you served us well. It's now time for you to rest.
tags: javascript
---

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.

```javascript
    var buttons = $("button.myclass")
```

In the DOM we now have [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/querySelector) and [querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/querySelectorAll). The first for selecting the first match, the latter for all matches. This can be called on the document, or any element.

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

This returns a [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList), which is _like_ an Array, but not quite. Importantly, you can subscript it like an array, and it has [forEach](https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach).

## Event listeners

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

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

In vanilla JS this is a little more verbose, using [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener):

```javascript
    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.

```javascript
    $('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:

```javascript
    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](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) method.

## Climbing the tree

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

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

As it happens, this is _easier_ in native JS:

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

## Manipulating classes

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

```javascript
    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](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList) attribute, which affords us even more power:

```javascript
    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:

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

The `classList`, which is a [DOMTokenList](https://developer.mozilla.org/en-US/docs/Web/API/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.

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

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

Again, modern DOMs provide [attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes), as a [NamedNodeMap](https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap): an unordered, live map of names to [Attr](https://developer.mozilla.org/en-US/docs/Web/API/Attr) instances.

```javascript
    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](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset), which is a [DOMStringMap](https://developer.mozilla.org/en-US/docs/Web/API/DOMStringMap).

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

And for the vanilla:

```javascript
    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.