jQuery is a fast, lightweight JavaScript library that simplifies DOM manipulation, event handling, AJAX calls, and animations. It was created in 2006 by John Resig to solve cross-browser compatibility issues that plagued raw JavaScript at the time. The core philosophy is “write less, do more” — a single line of jQuery often replaces many lines of vanilla JS.
Today, modern browsers handle most of what jQuery solved, but it remains widely used in legacy codebases and CMS platforms like WordPress.
// Vanilla JS — verbose
document.querySelectorAll(".btn").forEach(function(el) {
el.addEventListener("click", function() {
el.style.display = "none";
});
});
// jQuery — concise
$(".btn").on("click", function() {
$(this).hide();
});
$ is simply an alias for the jQuery function — they are identical. When called
with a CSS selector string, it returns a jQuery object wrapping all matched DOM elements. It can also wrap
existing DOM nodes, create new elements from HTML strings, or run a callback on DOM-ready.
// These are exactly equivalent
$("p");
jQuery("p");
// Selector — returns a jQuery object of all <p> elements
$("p").css("color", "red");
// Wrapping an existing DOM node
const el = document.getElementById("box");
$(el).addClass("active");
// Creating a new element
$("<div class='card'></div>").appendTo("body");
// DOM-ready shorthand
$(function() {
console.log("DOM is ready");
});
$(document).ready() fires when the HTML has been fully parsed and the DOM tree is built —
but before images and stylesheets finish loading. This ensures your jQuery code can safely find elements
by selector. Code placed outside this callback may run before the target elements exist in the DOM,
causing silent failures.
// Full form
$(document).ready(function() {
$("#menu").show();
});
// Shorthand — preferred
$(function() {
$("#menu").show();
});
// Avoid: runs immediately, <body> may not exist yet
$("#menu").show(); // ⚠️ could be null if script is in <head>
// Modern alternative: place <script> before </body>
// or use the defer attribute — no jQuery ready needed
Call jQuery.noConflict() to release $ back to the other library. jQuery still
works through the global jQuery name. Alternatively, wrap your code in an IIFE that receives
jQuery as the parameter named $ — so $ is scoped locally without
touching the global.
// Release $ globally
jQuery.noConflict();
jQuery("p").hide();
// IIFE pattern — $ is safe inside the function
(function($) {
$(function() {
$("p").addClass("highlight");
});
})(jQuery);
// Arrow function shorthand
jQuery(function($) {
$(".btn").on("click", function() { $(this).toggleClass("active"); });
});
A jQuery object is an array-like wrapper around one or more DOM elements. It exposes jQuery’s chainable
API methods like .css(), .on(), and .animate(). A raw DOM element
has none of these methods. You can convert between them with .get(index) or bracket notation
to unwrap, and $(el) to wrap.
// jQuery object — has jQuery methods
const $divs = $("div");
$divs.hide(); // jQuery method ✓
$divs.length; // number of matched elements
// Unwrap: jQuery → DOM element
const domEl = $divs.get(0); // first DOM element
const domEl2 = $divs[0]; // same thing
// Wrap: DOM element → jQuery object
$(domEl).show(); // back to jQuery
// Checking: jQuery objects are truthy even when empty!
if ($(".nonexistent").length) {
// correct check ✓
}
jQuery selectors mirror CSS selectors plus jQuery-specific extensions. The core categories are: basic
(tag, class, id, universal *), attribute-based, hierarchy (descendant, child
>, adjacent +), and filter pseudo-selectors like :first,
:last, :even, :odd, :eq(), :not(), and
:contains().
$("p") // all <p> tags
$(".card") // class selector
$("#hero") // id selector
$("ul > li") // direct children
$("h2 + p") // adjacent sibling
// Attribute selectors
$("[href]") // has href attribute
$("[type='checkbox']") // attribute equals value
$("[name^='user']") // attribute starts with
$("[href$='.pdf']") // attribute ends with
// Filter pseudo-selectors
$("li:first") // first <li>
$("li:last") // last <li>
$("tr:even") // 0-indexed even rows
$("tr:odd") // 0-indexed odd rows
$("li:eq(2)") // 0-indexed, third item
$("p:not(.hero)") // exclude .hero paragraphs
$("p:contains('jQuery')") // text content match
find() searches all descendants of the current set matching a selector.
filter() reduces the current set to only those elements that match a selector or pass a test
function. children() returns only immediate children — it does not go deeper than one level.
// Given: <ul id="nav"><li><a><span></span></a></li></ul>
$("#nav").find("span") // all <span> inside #nav (deep)
$("#nav").children("li") // only direct <li> children
$("#nav").children("li").find("a") // first children, then deep
// filter — narrows the existing matched set
$("li").filter(".active") // only .active li's
$("li").filter(function(i) {
return $(this).text().length > 5; // custom test
});
jQuery provides a full suite of traversal methods. Upward: parent(), parents(),
closest(). Downward: children(), find(). Sideways:
siblings(), next(), nextAll(), prev(),
prevAll(). closest() is the most useful — it walks up and returns the first
ancestor matching the selector.
$("span").parent() // immediate parent element
$("span").parents("div") // all ancestor <div>s
$("span").closest(".card") // first ancestor with .card
$(".card").children() // direct children only
$(".card").find("input") // all input descendants
$("li.active").siblings() // all siblings (not self)
$("li.active").next() // next sibling
$("li.active").prev() // previous sibling
$("li.active").nextAll() // all following siblings
$("li.active").prevAll() // all preceding siblings
// Common pattern: delegate handler uses closest()
$(document).on("click", ".delete-btn", function() {
$(this).closest(".item").remove();
});
.html() gets or sets the inner HTML of an element (equivalent to innerHTML).
.text() gets or sets the text content — HTML tags are escaped, preventing XSS when displaying
user input. .val() gets or sets the value of form fields like <input>,
<textarea>, and <select>.
// GET
$("#box").html() // "<strong>Hello</strong>"
$("#box").text() // "Hello" (strips tags)
$("#name").val() // "Alice" (input value)
// SET
$("#box").html("<em>World</em>") // renders the tag
$("#box").text("<em>World</em>") // shows literal text (safe ✓)
$("#name").val("Bob") // updates input field
// .text() for user-generated content prevents XSS ✓
const userInput = "<script>evil()</script>";
$(".output").text(userInput); // displayed as text, not executed
append() inserts content as the last child inside the target.
prepend() inserts as the first child inside. before() inserts content
before the target element (as a sibling). after() inserts content after the
target element (as a sibling). Each has an inverse form: appendTo(),
prependTo(), insertBefore(), insertAfter().
// <ul id="list"><li>Middle</li></ul>
$("#list").append("<li>Last</li>");
// → <ul><li>Middle</li><li>Last</li></ul>
$("#list").prepend("<li>First</li>");
// → <ul><li>First</li><li>Middle</li>...</ul>
$("#list").before("<h3>My List</h3>"); // sibling before ul
$("#list").after("<p>End</p>"); // sibling after ul
// Inverse forms — read as "insert X into/before/after Y"
$("<li>New</li>").appendTo("#list");
$("<li>Top</li>").prependTo("#list");
remove() deletes the element and all its event listeners from the DOM. detach()
removes the element but keeps its jQuery data and events intact — useful when you plan to reinsert it.
replaceWith() swaps the element for new content. clone(true) makes a deep copy
including all event handlers when true is passed.
// Remove permanently (events lost)
$("#old-banner").remove();
// Detach — keep events, reinsert later
const $item = $(".draggable").detach();
// ... do work ...
$("body").append($item); // events still work ✓
// Replace element with new content
$(".spinner").replaceWith("<p>Loaded!</p>");
// Clone without events
const $copy = $(".card").clone();
// Clone WITH events (deep copy)
const $copy2 = $(".card").clone(true);
$copy2.appendTo("#container");
.attr() gets or sets HTML attributes (like href, src,
disabled). .prop() gets or sets DOM properties (like checked,
disabled as booleans). .data() reads data-* attributes from HTML
and can store arbitrary jQuery-managed data on elements without touching the DOM.
// .attr() — HTML attributes (strings)
$("a").attr("href") // get
$("a").attr("href", "https://…") // set
$("img").attr({ src: "logo.png", alt: "Logo" }); // set multiple
// .prop() — DOM properties (correct for checkboxes)
$("input:checkbox").prop("checked") // true/false
$("input:checkbox").prop("checked", true) // check it
$("button").prop("disabled", true) // disable
// .data() — data-* attributes + jQuery store
// <div id="card" data-user-id="42" data-role="admin">
$("#card").data("userId") // 42 (camelCase, auto-converted)
$("#card").data("role") // "admin"
// Store custom data without DOM modification
$("#card").data("state", { open: true, page: 2 });
$("#card").data("state"); // { open: true, page: 2 }
jQuery’s class methods are addClass(), removeClass(),
toggleClass(), and hasClass(). They operate on the element’s
classList under the hood. You can pass multiple space-separated class names, or pass a
function that receives the current class string and returns the new one.
$(".btn").addClass("active");
$(".btn").addClass("active highlight large"); // multiple
$(".btn").removeClass("active");
$(".btn").removeClass("active highlight");
$(".btn").toggleClass("active"); // on if off, off if on
$(".btn").toggleClass("dark", isDark); // boolean switch
if ($(".btn").hasClass("active")) {
console.log("button is active");
}
// Dynamic class via function
$("li").addClass(function(index) {
return "item-" + index; // adds item-0, item-1, …
});
.css() gets the computed CSS value of a property (what the browser actually
renders, not just what’s in a stylesheet). Setting with .css() writes inline styles. You can
pass camelCase or kebab-case property names, and set multiple properties at once with an object literal.
// GET — returns computed value
$(".box").css("background-color"); // "rgb(255, 0, 0)"
$(".box").css("backgroundColor"); // same, camelCase works
// GET multiple at once
$(".box").css(["width", "height"]); // { width: "100px", height: "50px" }
// SET — writes inline style
$(".box").css("color", "red");
$(".box").css("font-size", "18px");
// SET multiple
$(".box").css({
color: "white",
background: "#7B2FBE",
padding: "12px 24px",
borderRadius: "8px"
});
jQuery provides .width() / .height() (content box), .innerWidth()
/ .innerHeight() (includes padding), and .outerWidth() /
.outerHeight() (includes padding + border, optionally margin). .offset() returns
position relative to the document; .position() returns position relative to the nearest
positioned ancestor.
$(".box").width() // content width (no padding)
$(".box").innerWidth() // width + padding
$(".box").outerWidth() // width + padding + border
$(".box").outerWidth(true) // + margin
$(".box").height()
$(".box").outerHeight(true)
// Position relative to document
const pos = $(".box").offset();
console.log(pos.top, pos.left);
// Position relative to parent
const relPos = $(".box").position();
console.log(relPos.top, relPos.left);
// SET dimensions
$(".box").width(200).height(100);
.on(event, handler) is the unified event binding API added in jQuery 1.7, replacing the
older .bind(), .live(), and .delegate(). Shorthand methods like
.click() are just wrappers around .on(). The key advantage is that
.on() also supports event delegation through an optional selector argument, making it work
for dynamically added elements.
// Direct binding — handler attached to matched elements only
$(".btn").on("click", function() {
console.log("clicked:", $(this).text());
});
// Delegated binding — works for future elements too
$(document).on("click", ".btn", function() {
console.log("delegated click");
});
// Multiple events on one handler
$("input").on("focus blur", function(e) {
console.log(e.type); // "focus" or "blur"
});
// Multiple events with different handlers (object form)
$(".card").on({
mouseenter: function() { $(this).addClass("hover"); },
mouseleave: function() { $(this).removeClass("hover"); }
});
.off() mirrors .on() to remove listeners. To remove a specific named handler,
use namespaced events (e.g. click.myPlugin). Passing the same function reference used in
.on() also works. Without arguments, .off() removes all listeners attached to
the matched elements.
// Remove all click handlers from .btn
$(".btn").off("click");
// Remove specific handler by reference
function handleClick() { console.log("clicked"); }
$(".btn").on("click", handleClick);
$(".btn").off("click", handleClick);
// Namespaced events — best practice for plugins / teardown
$(".btn").on("click.myFeature", handler);
$(".btn").off("click.myFeature"); // only removes .myFeature click
// Remove ALL events (use with caution)
$(".btn").off();
// One-time listener: fires once then auto-removes
$(".btn").one("click", function() {
console.log("fires only once");
});
e.preventDefault() stops the browser’s default action (form submit, link navigation).
e.stopPropagation() prevents the event from bubbling up to parent elements.
e.stopImmediatePropagation() additionally prevents other handlers on the same element from
firing. Returning false from a jQuery handler is shorthand for calling both
preventDefault() and stopPropagation().
// Prevent form submit reload
$("form").on("submit", function(e) {
e.preventDefault();
sendFormData($(this).serialize());
});
// Prevent link navigation
$("a.ajax-link").on("click", function(e) {
e.preventDefault();
loadContent($(this).attr("href"));
});
// Stop bubbling (click on child won't reach parent)
$(".dropdown-item").on("click", function(e) {
e.stopPropagation();
toggleItem(this);
});
// return false = preventDefault + stopPropagation
$("a").on("click", function() {
return false; // quick shorthand
});
.trigger() fires the specified event on the element, running all attached jQuery handlers
and the browser’s default behavior. .triggerHandler() fires only the jQuery handlers — it
does not bubble, does not trigger defaults, and returns the last handler’s return value instead of the
jQuery object.
// Simulate a click programmatically
$(".btn").trigger("click");
$(".btn").click(); // shorthand
// Submit a form without user action
$("form").trigger("submit");
// Trigger with extra data passed to handler
$(".btn").on("click", function(e, extra) {
console.log(extra); // "custom-data"
});
$(".btn").trigger("click", ["custom-data"]);
// Custom events
$(".card").on("cardFlipped", function(e, direction) {
console.log("flipped", direction);
});
$(".card").trigger("cardFlipped", ["left"]);
// triggerHandler — no bubbling, no default
$("input").triggerHandler("focus"); // focuses without scrolling
Event delegation attaches one listener to a stable parent element. When an event bubbles up from a child, jQuery checks if the target matches the selector — if so, it invokes the handler. This is efficient for large lists and essential for dynamically generated elements that don’t exist at bind time.
// Direct — only works for elements that exist NOW
$(".list-item").on("click", handler); // ⚠️ misses future items
// Delegated — works for current AND future .list-item elements
$("#list").on("click", ".list-item", function() {
console.log("clicked:", $(this).data("id"));
});
// Dynamically add item — click still works ✓
$("#list").append('<li class="list-item" data-id="99">New</li>');
// Best scope: use the closest stable ancestor, not document
// Good: $("#list").on("click", ".item", handler)
// OK: $("body").on("click", ".item", handler)
// Avoid: $(document).on("click", ".item", handler) — too broad
hide() sets display: none on the element. show() restores the
previous display value. toggle() switches between the two. All three accept an optional
duration (milliseconds or "fast"/"slow") to animate the transition, and an
optional callback that fires when the animation completes.
// Instant
$(".panel").hide();
$(".panel").show();
$(".panel").toggle();
// Animated — duration in ms
$(".panel").hide(400);
$(".panel").show("fast"); // 200ms
$(".panel").show("slow"); // 600ms
// With callback — runs after animation ends
$(".panel").hide(300, function() {
$(this).remove(); // remove after hiding ✓
});
// Toggle with a boolean condition
const isOpen = true;
$(".panel").toggle(isOpen); // show if true, hide if false
Fade effects animate opacity: fadeIn(), fadeOut(), fadeToggle(),
and fadeTo(duration, targetOpacity). Slide effects animate height: slideDown()
reveals an element, slideUp() collapses it, and slideToggle() alternates. Both
sets accept duration and callback arguments.
// Fade
$(".alert").fadeIn(400);
$(".alert").fadeOut(400, function() { $(this).remove(); });
$(".alert").fadeToggle(300);
$(".overlay").fadeTo(500, 0.5); // fade to 50% opacity
// Slide
$(".dropdown").slideDown(300);
$(".dropdown").slideUp(300);
$(".dropdown").slideToggle(300);
// Common accordion pattern
$(".section-header").on("click", function() {
$(this).next(".section-body").slideToggle(250);
$(this).toggleClass("open");
});
.animate() gradually transitions numeric CSS properties to target values. You can specify
duration, easing ("linear" or "swing" built-in), and a completion callback. Only
numeric properties can be animated (not colors without a plugin). Use .stop() before
re-triggering to prevent animation queuing.
// Animate multiple properties
$(".box").animate({
width: "300px",
opacity: 0.5,
left: "+=50px" // relative change
}, 600, "swing", function() {
console.log("animation done");
});
// Chain animations — jQuery queues them
$(".box")
.animate({ left: "200px" }, 400)
.animate({ top: "100px" }, 400)
.animate({ opacity: 0 }, 300);
// Stop current animation before restarting
$(".box").stop(true, true).animate({ left: 0 }, 300);
// stop(clearQueue, jumpToEnd)
$.ajax() is jQuery’s low-level AJAX function that returns a jqXHR object (a promise-like
deferred). All higher-level methods ($.get, $.post) are wrappers around it. Key
options are url, method, data, dataType,
contentType, headers, timeout, success, and
error.
$.ajax({
url: "/api/users",
method: "GET", // or "POST", "PUT", etc.
dataType: "json", // auto-parse response
data: { page: 1, limit: 20 },
timeout: 5000,
headers: { "Authorization": "Bearer " + token },
success: function(data) {
renderUsers(data.users);
},
error: function(jqXHR, status, errorThrown) {
console.error(status, errorThrown);
},
complete: function() {
hideSpinner(); // always runs ✓
}
});
// Promise style (preferred)
$.ajax({ url: "/api/users", dataType: "json" })
.done(function(data) { renderUsers(data); })
.fail(function(xhr) { showError(xhr.status); })
.always(function() { hideSpinner(); });
These are shorthand wrappers around $.ajax() for common patterns. $.get()
performs a GET request. $.post() performs a POST request. $.getJSON() performs a
GET request and automatically parses the JSON response. All return jqXHR objects for chaining
.done() / .fail().
// $.get(url, [data], [callback])
$.get("/api/products", { category: "books" }, function(data) {
renderProducts(data);
});
// $.post(url, data, [callback])
$.post("/api/login", { username: "ana", password: "123" })
.done(function(res) { redirectTo(res.dashboard); })
.fail(function(xhr) { showError(xhr.responseJSON.message); });
// $.getJSON — GET + auto-parse JSON
$.getJSON("/api/config").done(function(config) {
initApp(config);
});
// $.get with chained promise
$.get("/api/profile")
.done(function(user) { updateHeader(user.name); })
.fail(function() { showLoginPrompt(); });
.load(url [, data] [, callback]) fetches an HTML fragment and injects it directly into the
matched element’s innerHTML. You can optionally append a space-separated CSS selector to the URL to load
only a specific part of the response page. It is the simplest way to perform partial-page updates.
// Load full page HTML into #content
$("#content").load("/pages/about.html");
// Load only the #article part of the response
$("#content").load("/pages/about.html #article");
// With callback — fires after HTML is injected
$("#sidebar").load("/widgets/sidebar.html", function(response, status) {
if (status === "error") {
$(this).html("<p>Could not load sidebar.</p>");
}
});
// POST data with .load()
$("#results").load("/search", { q: "jquery", page: 1 }, function() {
$("#results a").on("click", openDetail); // bind after inject ✓
});
$.ajaxSetup() sets defaults applied to every subsequent $.ajax() call — useful
for base URLs, auth headers, or global error handling. Global AJAX events like ajaxStart and
ajaxStop fire on the document and are ideal for showing / hiding a site-wide loading spinner.
// Set defaults once at app startup
$.ajaxSetup({
contentType: "application/json",
headers: { "X-Auth-Token": sessionStorage.getItem("token") },
error: function(xhr) {
if (xhr.status === 401) redirectToLogin();
}
});
// Global spinner via AJAX events
$(document)
.ajaxStart(function() { $("#spinner").show(); })
.ajaxStop(function() { $("#spinner").hide(); });
// Disable global events for a specific call
$.ajax({ url: "/api/ping", global: false }); // spinner won't show
$.each(collection, callback) iterates over arrays and objects, passing
(index, value) to the callback. $.map(array, callback) creates a new array from
the return values (returning null removes the item). Note: the element method
$(...).each() passes (index, element) in the same order — this is
the element.
// $.each over array
$.each(["a", "b", "c"], function(index, value) {
console.log(index, value); // 0 "a", 1 "b", 2 "c"
});
// $.each over object
$.each({ name: "Ana", age: 28 }, function(key, val) {
console.log(key, val);
});
// Element method .each()
$("li").each(function(i, el) {
$(el).text("Item " + (i + 1));
});
// $.map — transforms array
const doubled = $.map([1, 2, 3], function(val) {
return val * 2;
}); // [2, 4, 6]
// Return null to filter out
const evens = $.map([1, 2, 3, 4], function(val) {
return val % 2 === 0 ? val : null;
}); // [2, 4]
$.extend(target, source1, source2, ...) merges source objects into the target, returning the
target. Properties from later sources overwrite earlier ones. Pass true as the first argument
for a deep (recursive) merge. It is commonly used to merge default options with user-provided options in
jQuery plugins.
// Shallow merge
const defaults = { color: "blue", size: 12, bold: false };
const userOpts = { color: "red", bold: true };
const options = $.extend({}, defaults, userOpts);
// { color: "red", size: 12, bold: true }
// defaults is unchanged ✓ (empty {} is the target)
// Deep merge
const a = { nested: { x: 1, y: 2 } };
const b = { nested: { y: 99, z: 3 } };
$.extend(true, a, b);
// a → { nested: { x: 1, y: 99, z: 3 } }
// Plugin pattern
function myPlugin(el, opts) {
const settings = $.extend({}, myPlugin.defaults, opts);
// use settings...
}
myPlugin.defaults = { speed: 300, easing: "swing" };
$.grep(array, fn) returns a new array containing only the elements for which the callback
returns true — similar to Array.prototype.filter().
$.inArray(value, array) returns the index of the value or -1 if not found (like
Array.indexOf). $.trim(str) removes leading and trailing whitespace.
// $.grep — filter array
const scores = [85, 42, 91, 55, 78];
const passing = $.grep(scores, function(score) {
return score >= 60;
}); // [85, 91, 78]
// Invert with third argument (true = return non-matching)
const failing = $.grep(scores, function(score) {
return score >= 60;
}, true); // [42, 55]
// $.inArray — returns index or -1
const fruits = ["apple", "banana", "cherry"];
$.inArray("banana", fruits); // 1
$.inArray("mango", fruits); // -1
if ($.inArray("banana", fruits) !== -1) {
console.log("found");
}
// $.trim — whitespace removal
$.trim(" hello world "); // "hello world"
.serialize() encodes form field values as a URL query string. .serializeArray()
returns an array of { name, value } objects — easier to transform into a plain object. Only
successful controls (not disabled, with a name) are included, following the W3C HTML specification.
// .serialize() — URL-encoded string
$("form").serialize();
// "username=Ana&email=ana%40example.com&role=admin"
// Send via AJAX
$.post("/api/profile", $("form").serialize());
// .serializeArray() — array of objects
$("form").serializeArray();
// [ { name: "username", value: "Ana" }, … ]
// Convert to plain object (jQuery way)
function formToObj(form) {
const obj = {};
$(form).serializeArray().forEach(function(item) {
obj[item.name] = item.value;
});
return obj;
}
const payload = JSON.stringify(formToObj("#myForm"));
$.ajax({ url: "/api/save", method: "POST",
contentType: "application/json", data: payload });
Most jQuery methods return the jQuery object they were called on, allowing multiple operations to be
chained in a single expression. This avoids repeated DOM lookups and makes the intent readable. Methods
that return a different set (like find()) can be un-done with .end() to restore
the previous selection.
// Without chaining — 3 DOM lookups
$("#box").addClass("active");
$("#box").css("color", "white");
$("#box").fadeIn(300);
// With chaining — 1 DOM lookup, 3 operations
$("#box").addClass("active").css("color", "white").fadeIn(300);
// .end() — return to previous selection
$("ul")
.find("li") // now working on <li>s
.addClass("item")
.end() // back to <ul>
.addClass("list"); // applies to <ul> ✓
// Chaining with traversal
$(".card")
.find("h2").css("font-weight", "700").end()
.find("p").css("color", "#555").end()
.addClass("loaded");
A $.Deferred() is jQuery’s implementation of the Promise pattern, predating native ES6
Promises. It exposes .resolve() / .reject() to settle the async operation, and
.done() / .fail() / .always() to register callbacks. The read-only
.promise() view can be returned to callers to prevent them from resolving or rejecting it
externally.
function loadImage(url) {
const dfd = $.Deferred();
const img = new Image();
img.onload = function() { dfd.resolve(img); };
img.onerror = function() { dfd.reject("Failed to load " + url); };
img.src = url;
return dfd.promise(); // return read-only promise ✓
}
loadImage("/photos/hero.jpg")
.done(function(img) { $("body").prepend(img); })
.fail(function(msg) { console.error(msg); })
.always(function() { hideSpinner(); });
// $.when — wait for multiple deferreds
$.when(
$.get("/api/user"),
$.get("/api/settings")
).done(function(userRes, settingsRes) {
const user = userRes[0];
const settings = settingsRes[0];
initApp(user, settings);
});
Plugins are added to $.fn (jQuery’s prototype). Every plugin should: (1) wrap code in an
IIFE accepting $ to avoid conflicts, (2) return this to preserve chaining, (3)
iterate with .each() so it works on multi-element sets, and (4) use $.extend to
merge default options.
(function($) {
$.fn.highlight = function(opts) {
const settings = $.extend({
color: "yellow",
duration: 400
}, opts);
return this.each(function() { // ← return this for chaining
$(this)
.css("background-color", settings.color)
.delay(settings.duration)
.queue(function(next) {
$(this).css("background-color", "");
next();
});
});
};
})(jQuery);
// Usage — chainable ✓
$("p.important")
.highlight({ color: "lightyellow", duration: 800 })
.addClass("processed");
$(document).ready() fires as soon as the HTML DOM is parsed — images and external resources
may still be downloading. $(window).on('load', fn) (or the native window.onload)
fires only after all resources on the page have fully loaded, including images and iframes. Use
load when you need actual image dimensions or must wait for third-party scripts.
// Fires when DOM is ready — images still loading
$(function() {
$("#gallery").masonry({ /* may get wrong heights */ });
});
// Fires when ALL resources are loaded
$(window).on("load", function() {
// Image natural dimensions are correct here ✓
$("img").each(function() {
console.log(this.naturalWidth, this.naturalHeight);
});
$("#gallery").masonry(); // layout after images are sized ✓
});
// Modern vanilla equivalent
window.addEventListener("DOMContentLoaded", handler); // = .ready()
window.addEventListener("load", handler); // = .on("load")
jQuery does not include debounce/throttle natively, but they are easy to implement.
Debounce delays execution until a burst of events stops — ideal for search-as-you-type.
Throttle limits execution to at most once per interval — ideal for scroll and resize
handlers. Lodash’s _.debounce / _.throttle are the standard library choice.
// Simple debounce implementation
function debounce(fn, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, arguments), delay);
};
}
// Debounced search — fires 300ms after typing stops
$("#search").on("input", debounce(function() {
$.get("/api/search", { q: $(this).val() })
.done(renderResults);
}, 300));
// Simple throttle implementation
function throttle(fn, limit) {
let inThrottle;
return function() {
if (!inThrottle) {
fn.apply(this, arguments);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
$(window).on("scroll", throttle(function() {
updateScrollProgress();
}, 100));
The context property on a jQuery object tells you where the DOM query was rooted.
When you call $("p"), the context is document. When you scope a query to a
specific node — $("p", "#sidebar") — the context is that node. Knowing the context is useful
for debugging scoped queries and for code that must distinguish a full-page search from a subsection
search.
// Global query — context is document
const $allLinks = $("a");
console.log($allLinks.context); // document
// Scoped query — context is the DOM element
const $navLinks = $("a", "#nav");
console.log($navLinks.context); // <nav id="nav">...
// Equivalent using find()
const $navLinks2 = $("#nav").find("a");
// Useful in plugins or handlers where you need to know
// the starting point of a search
$.fn.firstChild = function() {
console.log("Searching from:", this.context);
return this.children().first();
};
Every jQuery call returns a wrapper set — an array-like object holding zero or more
matched DOM elements. Methods called on the wrapper set operate on all elements simultaneously,
which is why $("p").hide() hides every paragraph without a loop. This “implicit iteration” is
the core power of jQuery: select once, act on many.
// Wrapper set may contain 0, 1, or many elements
$(".card").length; // e.g. 4
// All 4 cards get the class at once — no loop needed
$(".card").addClass("loaded");
// Iterating manually when you need per-element logic
$(".card").each(function(i, el) {
$(el).delay(i * 100).fadeIn(300); // staggered entrance
});
// Wrapper set is always returned even when empty
const $ghost = $(".nonexistent");
$ghost.length; // 0 — no error thrown ✓
$ghost.hide(); // no-op, no error ✓
// Check before acting
if ($ghost.length) {
$ghost.remove();
}
Loading jQuery from a public CDN (Google, jsDelivr, cdnjs) means visitors who have already cached that file from another site load it instantly. The tradeoff is a dependency on the CDN’s availability. A local fallback ensures your site works even if the CDN is unreachable.
<!-- Load from Google CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Fallback: if jQuery wasn't loaded, use local copy -->
<script>
window.jQuery || document.write(
'<script src="/js/jquery.min.js"><\/script>'
);
</script>
<!-- Modern alternative: module import -->
<script type="module">
import $ from "https://esm.sh/jquery";
$(function() { $("body").addClass("ready"); });
</script>
:nth-child(n) is a CSS pseudo-class that is 1-indexed and matches an
element only if it is the nth child of its parent — regardless of element type. :eq(n) is a
jQuery-specific filter that is 0-indexed and operates on the matched result set, not the
DOM position. :first is shorthand for :eq(0). This distinction causes surprising
bugs when the two are mixed up.
// :nth-child is 1-indexed and DOM-position aware
$("li:nth-child(1)") // FIRST li in each parent (index 1)
$("li:nth-child(2)") // SECOND li in each parent (index 2)
$("li:nth-child(odd)") // odd positions: 1, 3, 5…
$("li:nth-child(even)") // even positions: 2, 4, 6…
// :eq is 0-indexed, operates on the jQuery result set
$("li:eq(0)") // first li in the result set (index 0)
$("li:eq(1)") // second li in the result set (index 1)
$("li:first") // same as :eq(0)
$("li:last") // last li in the result set
// :nth-child(0) will NEVER match anything — starts at 1!
$("li:nth-child(0)"); // always empty ⚠️
jQuery selectors follow CSS selector syntax, so characters that have special meaning in CSS — like
., #, [, ], (, ),
:, ! — must be escaped with a double backslash (\\) when they
appear literally in an ID or class name. Forgetting this is a common source of “selector matched nothing”
bugs.
// Special characters that must be escaped:
// . # [ ] ( ) : ! @ $ % ^ & * + = | { } , < > ? / ~
// Element with id="user.name" (dot in ID)
$("#user\\.name") // ✓ escaped dot
// Element with id="price[0]" (brackets in ID)
$("#price\\[0\\]") // ✓ escaped brackets
// Element with class "col-2:sm" (colon in class)
$(".col-2\\:sm") // ✓ escaped colon
// Safe dynamic selector building — escape user input
function safeId(id) {
return "#" + $.escapeSelector(id); // jQuery 3+ built-in
}
$(safeId("user.name")).addClass("active");
// Alternatively, use attribute selector (no escaping needed)
$("[id='user.name']") // ✓ no escaping required
.is(selector) checks whether any element in the current set matches the given
selector, DOM element, jQuery object, or function — and returns true or false.
It does not create a new jQuery object, so it is the right tool for conditional checks without disrupting
a chain.
// Test against a CSS selector
$("input").is(":disabled") // true if any input is disabled
$(".btn").is(".active") // true if any .btn has .active
// Test against a DOM element
const el = document.getElementById("box");
$(".card").is(el) // true if el is one of the cards
// Test with a function (like filter, but returns boolean)
$("li").is(function() {
return $(this).text().length > 10;
});
// Practical: conditional action in event handler
$("input").on("change", function() {
if ($(this).is(":checked")) {
$("#options").slideDown(200);
} else {
$("#options").slideUp(200);
}
});
// Never check like this — empty set is truthy!
if ($(".nonexistent")) { /* always runs ⚠️ */ }
// Correct:
if ($(".nonexistent").length) { /* correct ✓ */ }
Use .prop("disabled", true/false) — never .attr("disabled", ...) for this
purpose. The disabled DOM property is a boolean, not a string attribute; .prop()
handles it correctly. Disabled elements are excluded from form serialization. jQuery’s
:disabled and :enabled filter selectors let you query their state.
// Disable a single element
$("#submit-btn").prop("disabled", true);
// Re-enable it
$("#submit-btn").prop("disabled", false);
// Disable all inputs in a form
$("form :input").prop("disabled", true);
// Check state with filter selectors
$("form :disabled").length // count of disabled fields
$("form :enabled").length // count of enabled fields
// Disable while an AJAX request is in-flight
$("#submit-btn").prop("disabled", true);
$.post("/api/save", data)
.always(function() {
$("#submit-btn").prop("disabled", false);
});
// Toggle based on a checkbox
$("#agree").on("change", function() {
$("#submit-btn").prop("disabled", !$(this).is(":checked"));
});
For checkboxes and radio buttons, always use .prop("checked") to read and set state — it
works with the live DOM property. Use .is(":checked") for a boolean test. To uncheck, set
checked to false with .prop(), or remove the attribute entirely
with .removeAttr("checked").
// Read state
const isChecked = $("#terms").prop("checked"); // true or false
const isChecked2 = $("#terms").is(":checked"); // same result
// Check / uncheck
$("#terms").prop("checked", true); // check
$("#terms").prop("checked", false); // uncheck
// Uncheck via removeAttr (older approach)
$("#terms").removeAttr("checked");
// Get all checked checkboxes in a group
const selected = [];
$("input[name='colors']:checked").each(function() {
selected.push($(this).val());
});
// e.g. ["red", "blue"]
// Get the selected radio button value
const gender = $("input[name='gender']:checked").val();
// Check all / uncheck all
$("#check-all").on("change", function() {
$("input[name='items']").prop("checked", $(this).is(":checked"));
});
.val() on a <select> returns the value of the currently selected
<option>. For a multiple select, it returns an array of selected values.
You can also target specific options with jQuery’s attribute or positional selectors to read or manipulate
the option list directly.
// Get selected value (single select)
const country = $("#country").val(); // e.g. "IL"
// Set selected option by value
$("#country").val("US");
// Multi-select — returns array
const langs = $("#languages").val(); // ["js", "css"]
// Set multiple selections
$("#languages").val(["js", "html", "css"]);
// Get selected option text (not value)
const label = $("#country option:selected").text();
// Select by position using filters
$("#select option:last").prop("selected", true); // last option
$("#select option:eq(3)").prop("selected", true); // 4th option (0-indexed)
$("#select option:gt(5)").remove(); // remove options after index 5
// Build dynamic options
const data = [{ val: "js", text: "JavaScript" }, { val: "py", text: "Python" }];
$.each(data, function(i, item) {
$("#language").append($("<option>", { value: item.val, text: item.text }));
});
A namespaced event appends a dot-separated label to the event name, e.g. click.myWidget.
This lets you remove only your handler without touching other handlers on the same element. It is
the correct pattern for plugins, components, and any code that needs a clean teardown. Multiple namespaces
are allowed: click.ns1.ns2.
// Bind with a namespace
$(".btn").on("click.myPlugin", function() { doWork(); });
$(".btn").on("mouseenter.myPlugin", function() { showHint(); });
// Remove only myPlugin's handlers — others untouched
$(".btn").off(".myPlugin");
// Multiple namespaces on one event
$(document).on("keydown.modal.a11y", handleKey);
$(document).off("keydown.modal"); // removes .modal regardless of .a11y
$(document).off("keydown.a11y"); // removes .a11y regardless of .modal
// Trigger only namespaced handlers
$(".btn").trigger("click.myPlugin"); // fires only .myPlugin click handler
// No depth limit on namespaces
$(".btn").on("click.components.buttons.primary", handler);
jQuery normalizes the browser event object across all browsers and adds a few useful properties. The most
important are event.type, event.target, event.currentTarget,
event.which (key/mouse button code), event.pageX / event.pageY,
event.data (custom data passed at bind time), and the event.originalEvent
reference to the raw native event.
$(document).on("click keydown", function(e) {
console.log(e.type); // "click" or "keydown"
console.log(e.target); // DOM element that triggered the event
console.log(e.currentTarget); // element the handler is attached to
console.log(e.which); // key code / mouse button number
console.log(e.pageX, e.pageY); // cursor position relative to document
console.log(e.originalEvent); // native browser Event object
});
// Passing custom data at bind time via event.data
$(".card").on("click", { id: 42, section: "hero" }, function(e) {
console.log(e.data.id); // 42
console.log(e.data.section); // "hero"
});
// Keyboard shortcut using e.which
$(document).on("keydown", function(e) {
if (e.which === 27) $(".modal").hide(); // Escape key
if (e.ctrlKey && e.which === 83) {
e.preventDefault();
saveDocument(); // Ctrl+S
}
});
Custom events are a powerful way to decouple components. You invent an event name, bind to it with
.on(), and fire it with .trigger(). Any data passed as the second argument to
.trigger() is received as extra parameters in the handler. Custom events bubble just like
native events, enabling parent-level listeners.
// Define custom event listeners
$(".cart").on("itemAdded", function(e, item, qty) {
console.log("Added:", item.name, "×", qty);
updateCartBadge(qty);
});
// Fire the custom event from anywhere
function addToCart(product, quantity) {
// ... business logic ...
$(".cart").trigger("itemAdded", [product, quantity]);
}
addToCart({ name: "jQuery Book", price: 9.99 }, 1);
// Custom events bubble — parent catches child's event
$(document).on("itemAdded", function(e, item) {
trackAnalytics("add_to_cart", item);
});
// Namespace custom events for clean teardown
$(".checkout").on("stepComplete.wizard", function(e, step) {
highlightStep(step);
});
// Later: remove only wizard's listeners
$(".checkout").off(".wizard");
Set jQuery.fx.off = true to instantly disable all animation methods site-wide — every
animate(), fadeIn(), slideDown(), etc. will complete immediately
with no transition. This is useful for accessibility (respecting the prefers-reduced-motion
media query), automated testing, or performance mode.
// Disable all jQuery animations globally
jQuery.fx.off = true;
// Now all animation methods jump to end state instantly
$(".panel").slideDown(500); // opens instantly, no 500ms transition
// Re-enable animations
jQuery.fx.off = false;
// Respect the user's OS preference (accessibility best practice)
const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)");
jQuery.fx.off = prefersReduced.matches;
// React to changes (user toggles OS setting)
prefersReduced.addEventListener("change", function(e) {
jQuery.fx.off = e.matches;
});
// Useful in tests: no waiting for animations
beforeEach(function() { jQuery.fx.off = true; });
afterEach(function() { jQuery.fx.off = false; });
:animated is a jQuery-specific pseudo-selector that matches elements currently in the
middle of a jQuery animation. It is useful for preventing duplicate triggers, adding visual
indicators during animations, or queuing work only after an animation completes. Note: it only tracks
jQuery animations, not CSS transitions.
// Prevent re-triggering while already animating
$(".btn").on("click", function() {
if ($(".panel").is(":animated")) return; // guard ✓
$(".panel").slideToggle(400);
});
// Add a CSS class while an element is animating
setInterval(function() {
$(".spinner").toggleClass("pulsing", $(".spinner").is(":animated"));
}, 100);
// Select all currently animating elements on the page
const $active = $(":animated");
console.log($active.length + " elements are animating");
// Stop all animations instantly
$(":animated").stop(true, true);
// Callback alternative — cleaner than :animated polling
$(".panel").slideDown(400, function() {
// runs after animation completes ✓
$(this).addClass("open");
});
By default, chained jQuery animation calls are queued — each one waits for the previous
to finish. To run animations at the same time (in parallel), pass all CSS property changes to a
single .animate() call. You can also pass { queue: false } to override
the queue for specific calls.
// Sequential — width first, then height (queued)
$(".box")
.animate({ width: "300px" }, 400)
.animate({ height: "200px" }, 400);
// Total duration: 800ms
// Simultaneous — width AND height at the same time
$(".box").animate({ width: "300px", height: "200px" }, 400);
// Total duration: 400ms ✓
// Mix: queue:false makes this run immediately
$(".box")
.animate({ width: "300px" }, { duration: 400 })
.animate({ opacity: 0.5 }, { duration: 400, queue: false });
// Both start at the same time ✓
// Run two separate elements in parallel (naturally parallel)
$(".box-a").animate({ left: "200px" }, 600);
$(".box-b").animate({ top: "100px" }, 600);
// Both run simultaneously — no special options needed ✓