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

jQueryVanilla JS
$("#id")document.getElementById("id")
$(".cls")document.querySelectorAll(".cls")
$(els).each(fn)els.forEach(fn)

Classes & content

jQueryVanilla 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

Try it yourself
Loading editor…
Press Run to see the result.

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().

Example · html
// 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.

Example · html
// 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.

Example · html
// 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

  • Be the first to comment on this lesson.