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
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
54 | 49 | No | 17 | 10 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
119 | 119 | 119 | 10.0-10.2 |
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.
Iterable NodeLists are so fundamentally important to the quality of the DOM. Unsurprisingly I now use React for most of my coding instead. — John Resig (@jeresig) April 29, 2016
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.
It's about time we have iterable NodeLists! https://t.co/nIT5uHALpW 🎉🎉🎉 Been asking for this for years! https://t.co/edb0TTSdop
— John Resig (@jeresig) April 29, 2016
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:
Performance recommendation: Do not use jQuery's hide() method. Ever. https://t.co/zEQf6F54p6
Classes are your friend.— Paul Irish (@paul_irish) February 8, 2015
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.
So, as always, you can’t do this in IE. So my company and I cannot use it.
At least we use Angular and can use the new behavior (sort of) that way.
Sure you can! That’s what polyfills are for. Still smaller than loading a library like jQuery, and you get all the modern goodness in older browsers.
You can’t do… what?
You can. You have to provide the polyfills, though. For example, for iterable
NodeList
objects, you could do this:NodeList.prototype.forEach = Array.prototype.forEach;
Yes, you’re extending the prototype of a native class. But that’s exactly how the W3C extended it, so no risk of collisions there.
Of course, you wouldn’t want to do this for all the features you’d want to use. So that’s why polyfill.io exists, it’s mentioned right in the article.
I’m gonna do it. By accident or on purpose, it’s definitely gonna happen.
I’m one of those people who has learned to write jQuery, but could not for the life of my write a line of pure JavaScript without StackOverflow helping me along the way. I like that these methods ‘read’ in a way that I feel is familiar and makes sense. Makes the learning curve a bit easer you know?
But I died a little inside when I saw that there is currently no native support on Microsoft Internet Explorer / Edge. I cannot imagine a single project that I have on my roster now or have had in the past oh… 5 years… that could just completely ignore IE. And if I have to rely on a poly to bridge the gap… I mean why not stick with jQuery at that point?
Because polyfilling only the features you need, on only the browsers that need it, is lighter than including all of jQuery for all browsers
I agree that it would be nice to ditch jQuery, but the cross browser support that it gives is invaluable.
I use jQuery a lot, and know only a little javascript, enough to get me by.
I have written full plugins in jQuery and wouldn’t know where to start with javascript.
On the whole I agree with you, but I don’t think it is up to the level of jQuery yet.
This might comes as shocking, but jQuery is JavaScript.
It’s baffling how people get confused by this. But really, JavaScript itself is a barebone but extensible language, and jQuery is the result of this extensibility. What you do not know is the plethora of native and browser APIs. And probably all the new ES6+ syntax.
Keep it up, jQuery is declining and you’re missing out!
I think probably everyone here understands that jQuery is an extension of JavaScript. But that doesn’t make jQuery exactly equivalent to JavaScript.
I went into this article expecting more absolutist conference bubble jQuery hate. What I got was a very insightful and enjoyable article.
I enjoyed the takeaway summarized in “What I Dislike About jQuery”. That is the real problem with jQuery going into the future, not it’s paradigm, but that it doesn’t work with vanilla JavaScript as seamlessly like newer frameworks are able to do.
I also enjoyed the section “Can’t Live Without $?”. Truth is, document.querySelector is painfully ugly and verbose, especially for something you might have to use several dozen times.
I find it strange how frequently I hear all about how horrible jQuery is, yet vanilla Javascript has taken many concepts from it, as shown beautifully in this article.
jQuery has done great things for the internet. I’m glad to see an article talk about alternatives to jQuery without the hate.
Regarding this part: “Truth is, document.querySelector is painfully ugly and verbose, especially for something you might have to use several dozen times.”
While I agree that it’s not easiest to read/write, I find it very helpful to take
querySelector
andquerySelectorAll
and make them into re-usable functions. With ES6 arrow functions and implicit returns, both can be made clear and concise.Last I checked Internet Explorer hovered at around 10% of the market but was falling fast. 2 more trips around the sun (mid 2019) and it will be in the 1% range.
It’s hard to say. StatCounter and W3Counter places IE+Edge at around 8% of the market, NetMarketShare suggests it’s closer to 18%.
What really matters is what browsers are being used by your viewers. These statistics are averages and don’t necessarily represent what you’re going to see if your visitors are centralized in a particular local, or if their background is particularly tech/non-tech, etc.
For example; a nightclub whose website I manage sees over 50% of their traffic from Safari. That’s not something you would assume given Safari’s marketshare… but their audience is younger club-goers who as it happens are more likely to own iPhones and so are more likely to use Safari.
Sometimes it’s not the actual users, but the CLIENT that you have to worry about. I have several that refuse to update or change browsers because of ancient systems that they have to use (computers and/or software), or out of sheer stubbornness.
I use mostly jQuery since I work on WordPress plugins and it has it preinstalled. I do think Vanilla JS is important to learn so now I have something new to work on!
This was my thought too. With all the talk of WordPress going with React or Vue (at least in the admin) in the future, I wonder if they’re considering ditching jQuery as being automatically included at some point?
One thought further: doing so would likely break a lot of themes.
I just tried the fade-in example you gave. Unless I’m missing something, there isn’t actually any fading happening.
I’d argue that you should use classes to toggle state anyways.
It seems like Firefox (55) doesn’t like transitioning from
display: none;
todisplay: block;
even whenrequestAnimationFrame()
is involved.It works fine
* in Chrome (well Vivaldi 1.8)
* in Firefox with
setTimeout()
* in Firefox when
display: block;
is set before the event handler gets executedPaul, the same, but I just wanted to try something that was in the article.
Doesn’t work in chrome either.
I have had this problem in the past. Usually, I would solve by adding a delay between the block and opacity, as it will cancel it out.
You could do it this way, but it could be gross
With
pointer-events: none
replacing
display: none
jQuery is like a faithful old blanket… Even when you have a spiffy new duvet – you still want ol’ blanky.
For much of the non-ajax API, you can still keep the
$
syntax by assigning it the value of thequerySelector
function.should actually be
window.$ = document.querySelectorAll
No, it shouldn’t:
remove
isn’t a method ofNodeList
objects.I forget where I heard it, but it’s been said that jQuery has been a massive success, in the sense that it fulfilled its ultimate goal. It was created because browser API’s at the time sucked, and it served as a public testing ground for developers to gradually refine the exact set of API’s they wanted to have available. Now that most of those have been adopted natively, jQuery can be put out to pasture with full honors, as the project that made browser API’s not suck.
Why don’t they just intergrate jQuery into browsers. Wouldn’t that be easier than waiting for javascript to be more like jQuery?
Most of this has excellent browser support, like queryselector is solid green all the way back to ie9. And you’d transpile to es5 anyway, with a polyfill loader, so lack of support really isn’t an issue any more.
Today, relying on jquery in an interview situation will get you rejected. Learn to live without jquery, the sooner the better.
You might get rejected out of hand if the the person who’s interviewing you is a bad developer. jQuery is not innately bad.
As the article states, there are vanilla JS/browser API issues related to iterating through NodeLists’s and Objects. jQuery provides some helpful wrappers for this with robust browser support, so depending on the types of sites and clients you support, using it is a no-brainer.
Most of the criticism of jQuery comes from bad developers doing bad things in it. Writing bloated code. Not understanding some of the performance issues related with using jQuery when there are better approaches.
Of course you don’t need jQuery. You don’t need Angular, you don’t need React, you don’t need Ember. But it sure makes things a hell of a lot easier and quicker to write. What about dynamic, clean html generation? What’s the substitution for a
$('<div />',{text: test, style: 'margin-top:30px', class: 'testclass' });
? Iterating a nodelist should be as simple as $(nodeList).each(function(i,item){ //do stuff }); jQuery will always be easier to use than vanilla JS. Why type outdocument.querySelector()
when you could just use$()
?Well, you’re right, you shouldn’t type document.querySelector everywhere. But you can do this:
const dsq = document.querySelector.bind(document);
and be done with it. You could even assign that to $ if you wanted to. Or:
const dsq = document.querySelector.bind(document);
const $ = (s) => Array.from(dsq(s));
(Because NodeLists might handle forEach, but not map, filter, and every.)
In ES6 you can do this with template strings and innerHTML:
If you want to do it properly you could write your own little utility function:
Or use a microlibrary like hyperx or virtual-dom/h to get JSX-like functionality.
Nice article, vanilla-js-purist in me is happy to see DOM APIs catch up so well.
A neat trick that I use is;
This with a library like ‘h’ is my defacto way of doing vanilla-js websites.
Just as a side note, you shouldn’t add event listener to each element. It will lead to poor performance and wouldn’t work with dynamically injected nodes. Instead it should be thrown on parent node (or whole
document
) which includes those elements.… it essentially means there are two duplicate ways of doing everything
I see this as a good thing rather than a bad thing. It’s jQuery’s way of doing things that is (in part) driving these new DOM methods and it’s a good thing that new concepts/methods/ways can be explored and refined in jQuery before they’re added to the DOM.
I love YMNNJQ! Great site, great open source project that is constantly evolving. I use it almost as much as I use JQuery.
for…of can iterate through a NodeList.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for…of
Like the other examples, if needs a polyfill, but, if you use Babel or any es6 transpiler, you can use it. :D
https://cdn.polyfill.io is very good as a concept.
Unfortunately, it still has too many bugs, and it doesn’t work as expected even in IE11. It can’t be used reliably in production.
If Jquery is not already preinstalled in the framework (bootstrap), I tend to use umbrella.js does everything I need https://umbrellajs.com/
Whoa… didn’t know about UmbrellaJS. That looks quite awesome!
Personally, I’ll probably still go native + polyfill, but for someone looking to tip-toe away from jQuery, that’s an awesome looking micro-library!
Is there an offline way to use polyfill.io? I’m currently working on an intranet project for a client and they don’t always have (direct) internet access and it’s a tedious process to get a domain cleared…
I wrote some code recently and I’m wondering if I can refactor is using the above methods. My code looks a div with id “about”, removes all the paragraphs in it, then creates new paragraphs within. Any improvements would be welcome.
Sooooo, the takeaway is: don’t use jQuery anymore because vanilla JavaScript is becoming more like jQuery.
I agree with a number of other people here that jQuery is much easier to write. It made instant sense to me when I found out about it around 2008, while JavaScript always seemed strange and muddled. But if vanilla JavaScript is becoming more like jQuery then maybe on that count jQuery has succeeded.
Ollie, good article.
But I still need to develop for IE, and there is STILL NO SUPPORT for these DOM methods. So I’ll continue using JQuery thank you very much. As it does support ALL the browsers I need to.
So your premise that we “might” not need to use JQuery is answered with your browser support table. Yes, we DO still need to use JQuery, if we are to support users of IE.
jQuery IS JavaScript, so… yes, vanilla JavaScript supports IE (I know, this is an obnoxious, semantic argument).
How far back are you talking? IE9+ covers 99.6% of the worldwide browser usage. IE8 supports
document.querySelector
, too. Some of the newer things listed above have relatively simple alternative approaches with broader browser support.And a few simple polyfills can push support for a lot of these all the way back to IE7.
One thing I am surprised that was not mentioned in the article is the performance of vanilla js vs jquery. There are a dozen of tests on jsperf and esbench that test simple everyday stuff that you do with jquery vs vanalla alternative and the results are astonishing. A few examples
https://jsperf.com/jquery-hide-vs-javascript-hide
https://jsperf.com/jquery-loop-appending/
https://jsperf.com/jquery-vs-native-balf
https://esbench.com/bench/574fab8ddb965b9a00965ace
Fortunately few of my users use IE or Edge – and I don’t have a problem telling those few to use something better.
I’d never program to a specific browser; but programming to the standard, and telling people who use a crap browser to switch, is different.
I understand that not everyone is in such a fortunate position, though.
Nice article, good point of view.
The weakest point, in my humble opinion, is relying on polyfill.io.
I wouldn’t want to rely on something that requires access to another external server for my whole site to work. That will instantly double the chances of a failure (be it server faults or network faults).
I would never want to rely on something that relies on checking the User-Agent header! Seriously in 2017 with all the device and browser kinds out there, phones, watches, IoT peripherals, should we rely on the User-Agent string?? No thanks. We didn’t do that in 1990, not going to start now. That’s what polyfill.io does.
I wouldn’t rely on something that is not totally stable. Even if they improve the code and fix bugs, that fix may change some behavior I unfortunately rely on. If I upgrade libraries my site relies on, I know about it, and I can test everything once again. If polyfill.io changes something, it doesn’t warn me about it, so nobody will test. New bugs may also be created, maybe for some minor platform and in that case nobody would know.
Polyfills are good but I like them the good ole way, on my own server and based on functionality, not User-Agent.
Unfortunately, that implies that you should install them yourself, know everything about all possible browsers, and failures that must be patched, to be sure for it all to work on 100% of your targets. It implies research and time spent finding all possible missing functions. That’s where JQuery comes handy, it just works (I won’t pull it from a cdn, as you probably guessed).
For projects that require few modern and stable browsers, some alternative library or none at all are ok, of course, and as time goes on they might become the norm. Just not yet.
You don’t even need Javascript to fade an element in, you can accomplish that with CSS.
I can honestly say that performance issues on websites I have worked on have never been caused by jQuery. If there are performance issues, it is either mis-use of jQuery and/or issues completely unrelated to the script.
It’s cool that native JS is now offering many of the reasons that motivated me to start using jQuery, and maybe as time goes by I’ll use some of them, but jQuery works and does not slow down the sites so I do not see a reason to abandon it.
In the past when I have used polyfills, they have broken sites on some browsers. I generally stay away from them. Sure the bugs get fixed but then new ones are introduced, and it seems by the time they really work well enough for production, they aren’t needed any more.
Thanks for the shout-out to Secrets of the JavaScript Ninja! But here’s a link to the 2nd Edition (rather than the 1st edition).
I’m waiting for the articles “React – considered harmful” and “You might not need React”. Though I guess I’ll just have to wait the obligatory ten years.
Hi
This is great. I’ve been using JS for the past year… was ActionScript up to then (yip, there are still some of us left!!) – tried to avoid jQuery as wanted to know what was going on under the hood.
Learning how JQuery works is very useful knowledge for a JS developer.
@Michael. True, but there is a lot to learn and I have to prioritize.
I’m mainly concerned with the OOD side of JavaScript, rather than DOM manipulation.
We use Angular v4 in work, and don’t install jQuery with that (I think that’s also the case with React). I need to know CSS, OOD JavaScript, and understand the HTML/DOM/JavaScriptVM/Rendering lifecycle. We deploy with webpack, npm, git, and use node.js (experss.js server side), MongoDB. There’s the particulars of the UI Framework – ngrx, component lifecycle, change detection, AOT compiling, server side rendering, third party library integration, TypeScript…… and thats about it . Easy peasy:-)
@Brian – but my point is that JQuery is more than just DOM manipulation. It’s a whole lesson on OOD in JS. Much of the design patterns you need to learn as a developer are used in this framework.
So, if you want to learn OOD, then my suggestion to get under the hood with JQuery still stands.
This is badass…
https://polyfill.io/v2/docs/
Just the polyfills you need for your site, tailored to each browser. Copy the code to unleash the magic:
https://cdn.polyfill.io/v2/polyfill.min.js
Polyfill.io reads the User-Agent header of each request and returns polyfills that are suitable for the requesting browser. Tailor the response based on the features you’re using in your app, and see our live examples to get started quickly.