You have now used jQuery for selecting, events, content, styles, traversing, effects, AJAX and forms. This last lesson puts it next to plain JavaScript – often called “vanilla” JavaScript – so you can read either style, move between them, and make a sensible choice for each project. That is the real question behind jQuery vs vanilla JavaScript: not which is better, but which suits the job.
jQuery vs vanilla JavaScript, side by side
Everything jQuery does is built on the same browser APIs you learned in the JavaScript track. Here are the everyday tasks in both styles:
| Task | jQuery 4 | Plain JavaScript |
|---|---|---|
| Run after the DOM is ready | $(() => { … }) | <script defer>, or DOMContentLoaded |
| Select one element | $('#menu') | document.querySelector('#menu') |
| Select many | $('.card') | document.querySelectorAll('.card') |
| Change every match | $('.card').addClass('on') | cards.forEach((c) => c.classList.add('on')) |
| Set text | $el.text('Hi') | el.textContent = 'Hi' |
| Listen for an event | $btn.on('click', fn) | btn.addEventListener('click', fn) |
| Delegate | $list.on('click', 'li', fn) | list.addEventListener('click', (e) => { const li = e.target.closest('li'); … }) |
| Nearest ancestor | $el.closest('.row') | el.closest('.row') |
| Read a data attribute | $el.data('price') | Number(el.dataset.price) |
| Show / hide | $el.hide() | el.hidden = true |
| Load JSON | $.getJSON(url) | fetch(url).then((r) => r.json()) |
For single elements, modern JavaScript is about as short as jQuery. jQuery saves the most typing when you work on many elements at once, chain several changes, or delegate events. The DOM side is covered in DOM Manipulation and JavaScript Events.
The same feature, written twice
Below, two “favourites” lists behave identically. The left one uses jQuery, the right one plain JavaScript. Compare the scripts line by line.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Favourites: jQuery and plain JavaScript</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
.cols { display: flex; flex-wrap: wrap; gap: 24px; }
.col { flex: 1 1 220px; }
li { margin: 4px 0; }
button.fav { background: #fef3c7; }
button.fav::after { content: " ★"; color: #d97706; }
</style>
</head>
<body>
<div class="cols">
<div class="col">
<h2>jQuery</h2>
<ul id="list-jq">
<li><button type="button">Idli</button></li><li><button type="button">Pongal</button></li><li><button type="button">Appam</button></li>
</ul>
<p id="count-jq" role="status"></p>
</div>
<div class="col">
<h2>Plain JavaScript</h2>
<ul id="list-js">
<li><button type="button">Idli</button></li><li><button type="button">Pongal</button></li><li><button type="button">Appam</button></li>
</ul>
<p id="count-js" role="status"></p>
</div>
</div>
<p>Click a dish to mark it as a favourite; click again to unmark it.</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
// ---- jQuery ----
function countJq() {
$('#count-jq').text(`${$('#list-jq .fav').length} favourite(s)`);
}
$('#list-jq').on('click', 'button', (event) => {
$(event.currentTarget).toggleClass('fav');
countJq();
});
countJq();
// ---- Plain JavaScript ----
const listJs = document.querySelector('#list-js');
const countEl = document.querySelector('#count-js');
function countJs() {
countEl.textContent = `${listJs.querySelectorAll('.fav').length} favourite(s)`;
}
listJs.addEventListener('click', (event) => {
const btn = event.target.closest('button');
if (!btn) return;
btn.classList.toggle('fav');
countJs();
});
countJs();
</script>
</body>
</html>Mixing jQuery and plain JavaScript
You do not have to choose one style per file. A jQuery object holds ordinary DOM elements, so you can step out and back in at any time:
$el[0]or$el.get(0)gives the first plain element;$el.get()gives a real array of all of them.$(element)wraps a plain element (or aNodeList) so you can use jQuery methods.- Inside jQuery callbacks such as
.each((i, el) => …)you receive plain elements, soel.classListandel.datasetwork directly.
const $inputs = $('#signup input');
// jQuery → plain: use the browser's validity API on each input
const allValid = $inputs.get().every((input) => input.checkValidity());
// plain → jQuery: wrap a native element to use jQuery helpers
const form = document.querySelector('#signup');
$(form).find('.error').empty();
// fetch() and jQuery together are fine too (inside an async function)
const res = await fetch('/api/cities');
$('#cities').append((await res.json()).map((c) => $('<li>').text(c.name)));Watch out: A common mix-up: calling a jQuery method on a plain element (document.querySelector('p').addClass('x')) or a DOM property on a jQuery object ($('p').classList). Both fail. The $ prefix on variables like $inputs helps you remember which is which.
What jQuery costs
jQuery is one more file to download and run before your own code. According to the jQuery 4 release notes, even the slim build (without AJAX and effects) is about 19.5 KB gzipped, and the full build is larger. That is small next to most images, but on a slow mobile connection every script that blocks interaction counts – see Core Web Vitals for designers.
An old argument was that visitors already had jQuery cached from the CDN because other sites used it. Modern browsers keep a separate cache for each site for privacy reasons, so that shared-cache benefit no longer applies. Judge jQuery on what it does for your own page.
So, should you use jQuery?
There is no single answer to jQuery vs vanilla JavaScript, but these guidelines hold up well in 2026:
- New small site or landing page: plain JavaScript is usually enough, and the page loads one less file.
- New app with lots of changing data: a component framework such as React fits better than either.
- Existing site built on jQuery: keep it, write consistent code in the same style, and plan an upgrade to jQuery 4 with the jQuery Migrate plugin.
- WordPress themes and plugins: jQuery is already available from core. Load it as a dependency of your script rather than adding your own copy, and remember the no-conflict wrapper
jQuery(($) => { … }). See WordPress theme development basics. - You need a jQuery plugin (a date picker or slider your team already uses): including jQuery is reasonable, but check for a maintained plain-JavaScript alternative first.
If you decide to move away from jQuery, do it gradually: replace one feature at a time, starting with the simplest (selectors, classes, text), then events, then AJAX with fetch(). Test after each step, and remove the jQuery script only when nothing uses $ any more. Your code editor’s search across files for $( and jQuery is a good final check.
Tip: Knowing both styles is the real skill. You can maintain the large amount of jQuery code that still runs the web, and you can write lean modern JavaScript when you start fresh. For a wider view, read Is jQuery still worth learning?
