Migrating Patterns to Vanilla JS
Translate the jQuery idioms you know into modern querySelector, fetch, classList and addEventListener.
If you know jQuery, you already understand the concepts — you just need the native vocabulary. Here is the translation table that turns muscle memory into modern JavaScript.
Selecting & looping
| jQuery | Vanilla JS |
|---|---|
$("#id") | document.getElementById("id") |
$(".cls") | document.querySelectorAll(".cls") |
$(els).each(fn) | els.forEach(fn) |
Classes & content
| jQuery | Vanilla JS |
|---|---|
.addClass("x") | .classList.add("x") |
.toggleClass("x") | .classList.toggle("x") |
.text("hi") | .textContent = "hi" |
.attr("href", u) | .setAttribute("href", u) |
Events
// jQuery
$("#btn").on("click", handler);
// Vanilla
document.querySelector("#btn").addEventListener("click", handler);
// Delegation, jQuery
$(list).on("click", "li", handler);
// Delegation, vanilla — check event.target inside one listener
list.addEventListener("click", function (e) {
if (e.target.closest("li")) handler.call(e.target, e);
});AJAX → fetch
// jQuery
$.getJSON("/api").done(function (data) { console.log(data); });
// Vanilla
fetch("/api")
.then(function (r) { return r.json(); })
.then(function (data) { console.log(data); });One gotcha worth remembering: querySelectorAll returns a static NodeList, not a live jQuery set, and it has no .addClass — you .forEach and touch each element's classList yourself. That per-element loop is exactly the work jQuery quietly did for you.
Example
When to use it
- A legacy jQuery site is being converted to framework-free vanilla JS; each jQuery call is replaced one file at a time during refactoring sprints.
- A developer documents a cheat sheet mapping each jQuery method to its vanilla equivalent for the team before removing the library.
- A performance audit finds that 85% of jQuery usage in a project is just selectors and class manipulation — replaceable with native APIs today.
More examples
Ready, selector, and text — vanilla style
DOMContentLoaded replaces $(document).ready(); getElementById and textContent replace the $() selector and .text().
// jQuery
$(function () {
$("#msg").text("Hello!");
});
// Vanilla JS
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("msg").textContent = "Hello!";
});Event listener and class toggle — vanilla
querySelectorAll with forEach and classList replaces the $() loop, removing the need for jQuery for tab switching entirely.
// jQuery
$(".tab").on("click", function () {
$(".tab").removeClass("active");
$(this).addClass("active");
});
// Vanilla JS
document.querySelectorAll(".tab").forEach(function (tab) {
tab.addEventListener("click", function () {
document.querySelectorAll(".tab").forEach(t => t.classList.remove("active"));
this.classList.add("active");
});
});AJAX with fetch replaces $.ajax()
fetch() with the options object maps cleanly to $.ajax() options, covering method, headers, and body without any library.
// jQuery
$.ajax({
url: "/api/data",
method: "POST",
contentType: "application/json",
data: JSON.stringify({ key: "value" }),
success: function (d) { console.log(d); }
});
// Vanilla JS
fetch("/api/data", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "value" })
}).then(r => r.json()).then(d => console.log(d));
Discussion