(Now More Than Ever) You Might Not Need jQuery

The DOM and native browser API's have improved by leaps and bounds since jQuery's release all the way back in 2006. People have been writing "You Might Not Need jQuery" articles since 2013 (see this classic site and this classic repo). I don't want to rehash old territory, but a good bit has changed in browser land since the last You Might Not Need jQuery article you might have stumbled upon. Browsers continue to implement new APIs that take the pain away from library-free development, many of them directly copied from jQuery.

Let's go through some new vanilla alternatives to jQuery methods.

Remove an element from the page

Remember the maddeningly roundabout way you had to remove an element from the page with vanilla DOM? el.parentNode.removeChild(el);? Here's a comparison of the jQuery way and the new improved vanilla way.

jQuery:

var $elem = $(".someClass") //select the element 
$elem.remove(); //remove the element

Without jQuery:

var elem = document.querySelector(".someClass"); //select the element
elem.remove() //remove the element

For the rest of this post, we'll assume that $elem a jQuery-selected set of elements, and elem is a native JavaScript-selected DOM element.

Prepend an element

jQuery:

$elem.prepend($someOtherElem);

Without jQuery:

elem.prepend(someOtherElem);

Insert an element before another element

jQuery:

$elem.before($someOtherElem);

Without jQuery:

elem.before(someOtherElem);

Replace an element with another element

jQuery:

$elem.replaceWith($someOtherElem);

Without jQuery:

elem.replaceWith(someOtherElem);

Find the closest ancestor that matches a given selector

jQuery:

$elem.closest("div");

Without jQuery:

elem.closest("div");

Browser Support of DOM manipulation methods

These methods now have a decent level of browser support:

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeOperaFirefoxIEEdgeSafari
544149NoNo10

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
10.0-10.2NoNo565954

They are also currently being implemented in Edge.

Fade in an Element

jQuery:

$elem.fadeIn();

By writing our own CSS we have far more control over how we animate our element. Here I'll do a simple fade.

.thingy {
  display: none;
  opacity: 0;
  transition: .8s;
}
elem.style.display = "block";
requestAnimationFrame(() => elem.style.opacity = 1);

Call an event handler callback only once

jQuery:

$elem.one("click", someFunc);

In the past when writing plain JavaScript, we had to call removeEventListener inside of the callback function.

function dostuff() {
  alert("some stuff happened");
  this.removeEventListener("click", dostuff);
}
var button = document.querySelector("button");
button.addEventListener("click", dostuff);

Now things are a lot cleaner. You might have seen the third optional parameter sometimes passed into addEventListener. It's a boolean to decide between event capturing or event bubbling. Nowadays, however, the third argument can alternatively be a configuration object.

elem.addEventListener('click', someFunc, { once: true, });

If you still want to use event capturing as well as have the callback called only once, then you can specify that in the configuration object as well:

elem.addEventListener('click', myClickHandler, {
  once: true,
  capture: true
});

Animation

jQuery's .animate() method is pretty limited.

$elem.animate({
  width: "70%",
  opacity: 0.4,
  marginLeft: "0.6in",
  fontSize: "3em",
  borderWidth: "10px"
}, 1500);

The docs say "All animated properties should be animated to a single numeric value, except as noted below; most properties that are non-numeric cannot be animated using basic jQuery functionality." This rules out transforms, and you need a plugin just to animate colors. You'd be far better off with the new Web Animations API.

var elem = document.querySelector('.animate-me');
elem.animate([
  { 
    transform: 'translateY(-1000px) scaleY(2.5) scaleX(.2)', 
    transformOrigin: '50% 0', 
    filter: 'blur(40px)', 
    opacity: 0 
  },
  { 
    transform: 'translateY(0) scaleY(1) scaleX(1)',
    transformOrigin: '50% 50%',
    filter: 'blur(0)',
    opacity: 1 
  }
], 1000);

Ajax

Another key selling point of jQuery in the past has been Ajax. jQuery abstracted away the ugliness of XMLHttpRequest:

$.ajax('https://some.url', {
  success: (data) => { /* do stuff with the data */ }
});

The new fetch API is a superior replacement for XMLHttpRequest and is now supported by all modern browsers.

fetch('https://some.url')
  .then(response => response.json())
  .then(data => {
    // do stuff with the data
  });

Admittedly fetch can be a bit more complicated than this small code sample. For example, the Promise returned from fetch() won't reject on HTTP error status. It is, however, far more versatile than anything built on top of XMLHttpRequest.

If we want ease of use though, there is a simpler option that has gained popularity - but it's not native to the browser, which brings me onto...

The Rise of the Micro-Library

Axios is a popular library for Ajax. It is a great example of a micro-library - a library designed to do just one thing. While most libraries will not be as well tested as jQuery, they can often an appealing alternative to the jQuery behemoth.

(Almost) Everything Can Be Polyfilled

So now you're aware that the DOM is now pretty nice to work with! But perhaps you've looked at these developments only to think "oh well, still need to support IE 9 so I better use jQuery". Most of the time it doesn't really matter what Can I Use says about a certain feature you want to utilize. You can use whatever you like and polyfills can fill in the gaps. There was a time when if you wanted to use a fancy new browser feature, you had to find a polyfill, and then include it on your page. Doing this for all the features missing in IE9 would be an arduous task. Now it's as simple

<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>

This simple script tag can polyfill just about anything. If you haven't heard about this polyfill service from the Financial Times you can read about it at polyfill.io.

Iterating a NodeList in 2017

jQuery's massive adoption hasn't solely been fostered by its reassuring ironing out of browser bugs and inconsistencies in IE Relics. Today jQuery has one remaining selling point: iteration.

It's defied rationality that NodeLists aren't iterable. Developers have had to jump through hoops to make them so. A classic for loop may be the most performance optimised approach, but sure isn't something I enjoy typing. And so we ended up with this ugliness:

var myArrayFromNodeList = [].slice.call(document.querySelectorAll('li'));

Or:

[].forEach.call(myNodeList, function (item) {...}

More recently we've been able to use Array.from, a terser, more elegant way of turning a nodeList into an array.

Array.from(querySelectorAll('li')).forEach((li) => /* do something with li */);

But the big news is that NodeLists are now iterable by default.

Now simply type:

document.querySelectorAll('li').forEach((li) => /* do some stuff */);

Edge is the last modern browser to not support iterable NodeLists but is currently working on it.

Is jQuery Slow?

jQuery may be faster than sloppily written vanilla JS, but that's just a good reason to learn JavaScript better! Paul Irish was a contributor to the jQuery project and concluded:

Here's what the creator of jQuery has to say about learning the native DOM in his (totally essential) Javascript book Secrets of the JavaScript Ninja:

"Why do you need to understand how it works if the library will take care of it for you? The most compelling reason is performance. Understanding how DOM modification works in libraries can allow you to write better and faster code."

What I Dislike About jQuery

Rather than smoothing over only the remaining ugly parts of certain browser API's, jQuery seeks to replace them all wholesale. By returning a jQuery object rather than a NodeList, built-in browser methods are essentially off limits, meaning you're locked into the jQuery way of doing everything. For beginners, what once made front-end scripting approachable is now a hindrance, as it essentially means there are two duplicate ways of doing everything. If you want to read others code with ease and apply to both jobs that require vanilla JS and jobs that require jQuery, you have twice as much to learn. There are, however, libraries that have adopted an API that will be reassuringly familiar to jQuery addicts, but that return a NodeList rather than an object...

Can't Live Without $?

Perhaps you've grown fond of that jQuery $. Certain micro-libraries have sought to emulate the jQuery API.

  • Lea Verou, an Invited Expert at the W3C CSS Working Group, who herself penned the article jQuery Considered Harmful is the author of Bliss.js. Bliss uses a familiar $ syntax but returns a NodeList.
  • Paul Irish, meanwhile, released Bling.js "because you want the $ of jQuery without the jQuery."
  • Remy Sharp offered a similar micro-library, aptly named min.js.

I'm no anti-jQuery snob. Some great developers still choose to use it. If you're already comfortable using it and at home with its API, there's no huge reason to ditch it. Ultimately there are people who use jQuery and know what a closure is and who write enterprise-level web apps, and people who use vanilla JS who don't. Plenty of jobs still list it as a required skill. For anybody starting out though, it looks like an increasingly bad choice. Internet Explorer 11 is thankfully the final version of that infernal contraption. As soon as IE dies the entire browser landscape will be evergreen, and jQuery will increasingly be seen as a bygone relic from the DOM's dirty past.


(Now More Than Ever) You Might Not Need jQuery is a post from CSS-Tricks