Cheatsheet jQuery
Biblioteca JavaScript para manipulação DOM
jQuery
Selectors
Document ready
// Full form:
$(document).ready(function() {
// DOM loaded and safe
});
// Short form (recommended):
$(function() {
// equivalent to ready
});
// Multiple ready (all run):
$(function() { console.log("module A"); });
$(function() { console.log("module B"); });Ensures the DOM is fully parsed before running code. The short form $(fn) is identical to $(document).ready(). Multiple handlers run in registration order. Unlike window.onload, it does not wait for images/CSS.
Position filters
$("li:first") // first li on the page
$("li:last") // last li
$("li:eq(2)") // index 2 (third)
$("li:gt(3)") // index greater than 3
$("li:lt(3)") // index less than 3
$("li:even") // even indices (0, 2, 4...)
$("li:odd") // odd indices (1, 3, 5...)
// Equivalent with method (faster):
$("li").first()
$("li").last()
$("li").eq(2)Position pseudo-selectors filter by index in the collection. :eq(n) is zero-based. The method versions (.first(), .eq()) are faster than pseudo-selectors because they filter after the CSS selection. :even/:odd are useful for striping tables.
find() and filter()
// find(): searches INSIDE the selected
$("ul").find("li.active") // li inside ul
$("#form").find("input") // inputs inside the form
// filter(): reduces the current selection
$("li").filter(".active") // only those with the class
$("li").filter(function(i) {
return $(this).data("type") === "special";
});
// Difference:
$("div").find("p") // p INSIDE div
$("div").filter("p") // divs that are ALSO p (nothing)find() searches descendants of the selected elements. filter() reduces the current collection by a selector or function. find() goes down the tree; filter() evaluates the elements themselves. Both accept a callback function for complex logic.
Element selector
$("p") // all paragraphs
$("div") // all divs
$("li") // all list items
$("h1, h2") // multiple types (comma = OR)
// Returns a jQuery object (array-like):
var paragrafos = $("p");
paragrafos.length; // number found
paragrafos[0]; // first DOM element (raw)Selects all elements of the given type. Returns a jQuery object (collection), not a DOM element. The .length property indicates how many were found. Accessing [0] returns the native element (without jQuery methods).
State filters
$(":button") // all buttons
$(":checkbox") // checkboxes
$(":radio") // radio buttons
$(":checked") // checked (checkbox/radio)
$(":selected") // selected option
$(":disabled") // disabled fields
$(":enabled") // enabled fields
$(":focus") // focused element
$(":hidden") // invisible (display:none)
$(":visible") // visibleState filters select by AS element's current condition. :checked and :selected change with user interaction. :hidden includes display:none, visibility:hidden and zero-width/height elements. They re-evaluate on every call (do not use in loops).
Context and scope
// Second parameter = context (limits the search):
$("li", document.getElementById("menu"))
// equivalent to:
$("#menu").find("li")
// this inside handlers:
$(".btn").click(function() {
$(this) // clicked element (jQuery)
this // clicked element (DOM raw)
this.textContent // without jQuery
});
// each() with context:
$("li").each(function() {
$(this).addClass("visto"); // each li
});The second parameter of $() limits the search context (faster in subtrees). Inside handlers, this refers to the native DOM element; $(this) wraps it in jQuery to use methods. In .each(), this changes on each iteration. Arrow functions lose this — use function().
Class and ID
$(".menu") // class="menu"
$("#header") // id="header"
$(".card.active") // card AND active (both)
$("div.box") // div with class="box"
// ID is faster (uses getElementById):
$("#unico") // very fast
$(".many") // uses querySelectorAllA dot (.) selects by class, a hash (#) by id. Combine the in CSS: .card.active requires both classes. IDs are more performant since they use the native getElementById. Classes use querySelectorAll internally.
Attribute selector
$("[href]") // has href attribute
$("[type='text']") // exact type
$("[href^='https']") // starts with
$("[href$='.pdf']") // ends with
$("[class*='btn']") // contains substring
$("[data-id]") // has data-attribute
$("input[name='email']") // input with name
// Combine:
$("a[target='_blank'][rel='noopener']")Brackets [] filter by attribute. ^= prefix, $= suffix, *= contains, = exact. They can be combined with each other and with other selectors. Useful for custom data-attributes. Slower than class/ID — prefer those when possible.
Custom selectors
// jQuery adds non-CSS selectors:
$(":input") // input, textarea, select, button
$(":text") // input[type=text]
$(":password") // input[type=password]
$(":file") // input[type=file]
$(":image") // input[type=image]
$(":submit") // input/button submit
$(":reset") // input/button reset
$(":header") // h1, h2, h3, h4, h5, h6
$(":animated") // animating elements
$(":button") // button and input[type=button]The :input selector and its derivatives are exclusive to jQuery (they do not exist in CSS). :input selects all form fields at once. :header selects all headings. :animated detects elements with an active animation. Useful but slower — use sparingly.
Combined selectors
$("ul li") // descendant (any level)
$("ul > li") // direct child (only 1 level)
$("h2 + p") // next sibling (adjacent)
$("h2 ~ p") // all following p siblings
// Practical example:
$("nav > ul > li > a") // direct links in the menuSpace = descendant (any depth). > = direct child. + = immediately following sibling. ~ = all following siblings of the same type. The more specific, the faster the selection.
Content selector
$("p:contains('error')") // text contains "error"
$("td:empty") // empty cells
$("div:has(img)") // divs that contain img
$("p:parent") // elements with children
// :has() is powerful:
$("li:has(> a.active)") // li with a direct active link
$("form:has(input:visible)") // forms with visible fields:contains() filters by text (case-sensitive). :has() selects parents that contain a given child — very versatile. :empty has no children or text. :parent is the opposite of :empty. These are jQuery selectors (not native CSS), therefore slower.
Selector performance
// FAST → SLOW:
$("#id") // 1. getElementById
$(".class") // 2. getElementsByClassName
$("div.class") // 3. tag + class
$("[data-x]") // 4. attribute
$("div:visible") // 5. pseudo-selector
// Performance tips:
var $list = $("#list"); // cache!
$list.find("li.active"); // context
$list.children(".item"); // direct children
// Avoid:
$("div .item") // too generic
$("*") // all elements
$("li:eq(0):visible") // multiple filtersPerformance order: #id > .class > tag.class > [attr] > :pseudo. cache repeated selections in variables ($ prefix by convention). Use .find() with context instead of long selectors. Avoid $("*") and chained pseudo-selectors.
Events
on() — event binding
// Recommended method (jQuery 1.7+):
$("#btn").on("click", function() {
alert("clicado!");
});
// Multiple events:
$("#field").on("focus blur", function() {
$(this).toggleClass("active");
});
// Events object:
$("#form").on({
submit: function(e) { e.preventDefault(); },
reset: function() { clear(); }
});on() is the universal event method (it replaces bind(), live(), delegate()). It accepts a string with space-separated events or an object. The handler receives the event object with details. Always prefer on() over shortcuts like .click().
Keyboard events
$("input").on("keydown", function(e) {
console.log(e.key); // "a", "Enter", "Escape"
console.log(e.code); // "KeyA", "Enter"
console.log(e.which); // numeric code
// Detect special keys:
if (e.key === "Enter") { send(); }
if (e.key === "Escape") { close(); }
if (e.ctrlKey && e.key === "s") {
e.preventDefault();
save();
}
});
// keypress (printable characters only):
$("input").on("keypress", fn);keydown fires when pressing any key (including special ones). e.key gives the readable value, e.code the physical key. e.ctrlKey, e.shiftKey, e.altKey detect modifiers. keypress is deprecated — use keydown. preventDefault() cancels the native action (e.g. Ctrl+S).
trigger() — fire events
// Fire an event programmatically:
$("#btn").trigger("click");
$("#form").trigger("submit");
// Short form:
$("#btn").click(); // fires click
$("#form").submit(); // fires submit
// With extra data:
$("#btn").trigger("click", ["extra1", "extra2"]);
// The handler receives:
$("#btn").on("click", function(e, extra1, extra2) {
console.log(extra1); // "extra1"
});
// Custom event:
$("#app").trigger("data:carregados", [data]);
$("#app").on("data:carregados", function(e, data) {
render(data);
});trigger() fires events programmatically (the if the user clicked). It accepts extra data the an array in the second parameter. Custom events (with a namespace) create communication between modules. The short form .click() without arguments fires the event. Useful for tests and coordinating components.
off() — remove events
// Remove all clicks:
$("#btn").off("click");
// Remove ALL events:
$("#btn").off();
// Specific handler (named function):
function handler() { console.log("oi"); }
$("#btn").on("click", handler);
$("#btn").off("click", handler);
// Namespaces:
$("#btn").on("click.app", fn1);
$("#btn").on("click.modal", fn2);
$("#btn").off("click.app"); // only removes fn1off() removes handlers previously bound with on(). Without arguments it removes everything. Namespaces (.app, .modal) allow removing specific groups without affecting others. Essential to avoid memory leaks when destroying components. Anonymous functions cannot be removed selectively.
Form events
$("form").on("submit", function(e) {
e.preventDefault();
var data = $(this).serialize();
// send via AJAX
});
$("input").on("change", function() {
// value changed AND lost focus
console.log($(this).val());
});
$("input").on("input", function() {
// fires on EVERY keystroke (real time)
filter($(this).val());
});
$("select").on("change", function() {
load($(this).val());
});submit intercepts the form submission. change fires when the value changes and the field loses focus. input fires on every keystroke (ideal for real-time search). serialize() converts the form into a query string. Always preventDefault() on submit to avoid a page reload.
Event object
$("#box").on("click", function(event) {
event.type; // "click"
event.target; // clicked element (DOM)
event.currentTarget; // element with the handler (= this)
event.pageX; // X position (document)
event.pageY; // Y position (document)
event.timeStamp; // when it happened
// Which mouse button:
event.which; // 1=left, 2=middle, 3=right
// Modifier keys:
event.ctrlKey; // Ctrl pressed?
event.shiftKey; // Shift pressed?
event.altKey; // Alt pressed?
event.metaKey; // Cmd (Mac) pressed?
});The event object contains all the details of the interaction. target is what originated it; currentTarget is what has the handler. pageX/pageY for the mouse position. which identifies the mouse button or key. Boolean properties (ctrlKey, shiftKey) for combinations. Normalized by jQuery (cross-browser).
Event delegation
// Event on the PARENT, filter on the child selector:
$("#list").on("click", "li", function() {
$(this).toggleClass("done");
});
// Works with future elements:
$("#list").append("<li>New</li>");
// clicking the new li works automatically!
// Without delegation (does NOT work with dynamic ones):
$("li").on("click", fn); // only the existing ones
// Multiple selectors:
$("#table").on("click", "td, th", fn);Delegation: the event binds to the parent and filters by the child selector. It works with elements created after the binding. The event "bubbles" from the child up to the parent. More efficient: 1 handler on the parent vs N handlers on the children. Essential for dynamic lists, tables and AJAX content.
preventDefault and stopPropagation
$("a").on("click", function(e) {
e.preventDefault(); // cancels navigation
// do something custom (AJAX, modal...)
});
$(".dropdown").on("click", function(e) {
e.stopPropagation(); // does not close the parent menu
$(this).toggleClass("open");
});
// return false = both:
$("a").on("click", function() {
return false; // preventDefault + stopPropagation
});
// Check whether it was cancelled:
if (e.isDefaultPrevented()) { /* ... */ }preventDefault() cancels the native action (navigation, submit). stopPropagation() prevents the event from rising up the DOM tree (bubbling). return false in a jQuery handler does both. isDefaultPrevented() checks whether another handler already cancelled it. Use with care — stopPropagation can break delegation.
ready vs load vs DOMContentLoaded
// DOM ready (no images/CSS):
$(function() {
// manipulate the DOM safely
});
// Everything loaded (images, CSS, fonts):
$(window).on("load", function() {
// compute real dimensions
var height = $("#hero img").height();
});
// Vanilla equivalent to ready:
document.addEventListener("DOMContentLoaded", fn);
// Script at the end of the body (alternative):
// <script src="app.js"></script> before </body>$(fn) / ready fires when the HTML is parsed (it does not wait for resources). $(window).on("load") waits for everything (images, CSS, fonts). To manipulate the DOM, ready is enough. For image dimensions, use load. Scripts at as end of <body> make ready unnecessary (the DOM already exists).
Mouse events
$("#box").on({
mouseenter: function() { $(this).addClass("hover"); },
mouseleave: function() { $(this).removeClass("hover"); },
mousedown: function() { $(this).addClass("press"); },
mouseup: function() { $(this).removeClass("press"); },
});
// hover() = mouseenter + mouseleave:
$("#box").hover(
function() { $(this).fadeIn(); }, // enter
function() { $(this).fadeOut(); } // leave
);
// Mouse coordinates:
$(document).on("mousemove", function(e) {
console.log(e.pageX, e.pageY);
});mouseenter/mouseleave do not fire on children (unlike mouseover/mouseout). hover() is a shortcut for both. e.pageX/e.pageY give coordinates relative to the document. mousedown/mouseup for press effects. Use delegation for dynamic elements.
one() — run once
$("#btn").one("click", function() {
alert("Only appears ONCE!");
});
// second click: nothing happens
// Useful for initializations:
$("#app").one("scroll", function() {
loadHeavyData();
});
// With delegation:
$("#list").one("click", "li", function() {
$(this).addClass("first-click");
});
// Note: one() with delegation fires once PER elementone() binds a handler that auto-removes after the first execution. Ideal for tutorials, lazy loading and one-off initializations. With delegation, it fires once per child element (not globally). Equivalent to binding with on() and calling off() inside the handler.
DOM manipulation
Creating elements
// Create with an HTML string:
var $item = $("<li>New item</li>");
var $card = $('<div class="card"><h3>Title</h3></div>');
// With attributes:
var $link = $("<a>", {
text: "Click here",
href: "/page",
class: "btn btn-primary",
target: "_blank"
});
// Create and insert:
$("#list").append($item);
$("body").append($card);Passing HTML to $() creates elements (it does not select). The second parameter (object) defines attributes and properties. The element stays in memory until inserted into the DOM. Variables with a $ prefix indicate jQuery objects by convention. Creating outside the DOM and inserting once is more performant.
html() and text()
// html(): reads/sets the inner HTML
var content = $("#box").html();
$("#box").html("<strong>Bold</strong>");
// text(): reads/sets only text (no tags)
var text = $("#box").text();
$("#box").text("Sem <b>tags</b>"); // literal
// Difference:
// html("<b>oi</b>") → shows "oi" in bold
// text("<b>oi</b>") → shows "<b>oi</b>" literally
// Security: text() escapes automatically
$("#name").text(userInput); // safe (XSS)html() works with HTML (interprets tags). text() works with plain text (escapes tags). Without arguments they read; with an argument they set. Use text() for user content (prevents XSS). html() replaces all the inner content at once.
each() — iterate elements
// Iterate over a jQuery collection:
$("li").each(function(index, element) {
$(element).text((index + 1) + ". " + $(element).text());
});
// this = current element:
$(".card").each(function() {
var title = $(this).find("h3").text();
$(this).attr("title", title);
});
// Stop the iteration:
$("li").each(function() {
if ($(this).hasClass("stop")) return false;
$(this).addClass("visto");
});each() iterates over each element of the collection. this refers to the current DOM element (wrap with $(this) for jQuery methods). return false inside the callback stops the iteration (like break). The callback receives (index, element). Do not confuse it with $.each() (for arrays/objects).
append() and prepend()
// append(): inserts at the END (inside)
$("#list").append("<li>Last</li>");
$("#list").append($("<li>").text("Other"));
// prepend(): inserts at the START (inside)
$("#list").prepend("<li>First</li>");
// Multiple at once:
$("#list").append(
"<li>A</li>",
"<li>B</li>",
"<li>C</li>"
);
// appendTo() (reverse):
$("<li>End</li>").appendTo("#list");
$("<li>Top</li>").prependTo("#list");append() inserts at the end of the children; prepend() at the start. They accept multiple arguments, HTML strings or jQuery objects. appendTo()/prependTo() are the reversed form (useful for chaining). They all insert inside the target element, the children.
clone()
// Clone without events:
var $copy = $("#card").clone();
$("#gallery").append($copy);
// Clone WITH events and handlers:
var $copy2 = $("#card").clone(true);
// Clone with events + descendants:
var $copy3 = $("#card").clone(true, true);
// Modify the clone before inserting:
var $new = $("#template").clone()
.attr("id", "card-" + nextId)
.find(".title").text("New").end();
$("#list").append($new);clone() duplicates the element. Without arguments, it does not copy events. clone(true) copies the element's handlers; clone(true, true) also copies the descendants'. The clone is independent — modifying one does not affect the other. Ideal for templates: clone, customize and insert.
map() — transform a collection
// Extract values:
var texts = $("li").map(function() {
return $(this).text();
}).get(); // .get() converts to a real array
// Transform:
var ids = $(".card").map(function() {
return $(this).data("id");
}).get();
// $.map() (for arrays/objects):
var dobros = $.map([1, 2, 3], function(n) {
return n * 2;
}); // [2, 4, 6]
// grep (filter an array):
var even = $.grep([1,2,3,4,5], function(n) {
return n % 2 === 0;
}); // [2, 4].map() transforms each element and returns a new jQuery collection. .get() converts to a native array. $.map() is the static version for arrays/objects. $.grep() filters arrays (equivalent to Array.filter). Useful for extracting data from multiple elements at once.
before() and after()
// before(): inserts BEFORE (sibling)
$("#target").before("<p>Before me</p>");
// after(): inserts AFTER (sibling)
$("#target").after("<p>After me</p>");
// insertBefore() / insertAfter() (reverse):
$("<p>New</p>").insertBefore("#target");
$("<p>New</p>").insertAfter("#target");
// Difference from append:
// append/prepend → INSIDE (child)
// before/after → OUTSIDE (sibling)before() and after() insert the siblings (outside the element). append()/prepend() insert the children (inside). insertBefore()/insertAfter() are the reversed versions. They all accept an HTML string, jQuery object or DOM element.
wrap() and unwrap()
// wrap(): wraps each element
$("p").wrap("<div class='wrapper'></div>");
// each <p> ends up inside a div
// wrapAll(): wraps ALL in one
$("p").wrapAll("<div class='group'></div>");
// wrapInner(): wraps the CONTENT
$("#box").wrapInner("<span class='internal'></span>");
// unwrap(): removes the PARENT (unwraps)
$("p").unwrap(); // removes the wrapper div
// Example: highlight text
$("p").wrapInner("<mark></mark>");wrap() wraps each element individually. wrapAll() wraps them all in a single wrapper. wrapInner() wraps the content (children) without moving the element. unwrap() removes the direct parent. Useful for adding structure without rewriting HTML.
Chaining
// Methods return the jQuery object:
$("#box")
.addClass("active")
.css("color", "red")
.fadeIn(300)
.find("span")
.text("Hello");
// end() goes back to the previous selection:
$("#menu")
.find(".item").addClass("visto")
.end() // back to $("#menu")
.find(".badge").text("3")
.end(); // back to $("#menu")
// Without chaining (repetitive):
var $c = $("#box");
$c.addClass("active");
$c.css("color", "red");Almost all jQuery methods return this, allowing chaining. end() reverts to the previous selection on the stack. Chaining improves readability and avoids repeated variables. Careful: find(), filter(), children() change the selection — use end() to go back.
remove() and detach()
// remove(): deletes from the DOM + events + data
$("#item").remove();
$("li.done").remove(); // multiple
// With a filter:
$("li").remove(".old");
// detach(): deletes but KEEPS events/data
var $el = $("#widget").detach();
// ... later:
$("#sidebar").append($el); // events intact
// empty(): removes only the CHILDREN
$("#container").empty(); // becomes empty but still existsremove() removes the element and all its associated events and data. detach() removes from the DOM but preserves events/data in memory (to reinsert later). empty() removes only the children, keeping the parent. Use remove() in most cases; detach() to move elements.
replaceWith() and replaceAll()
// replaceWith(): replaces the element
$("#old").replaceWith("<div class='new'>New</div>");
// With a function (dynamic replacement):
$("li").replaceWith(function(i) {
return "<p>" + $(this).text() + "</p>";
});
// replaceAll() (reverse):
$("<span>N/A</span>").replaceAll(".empty");
// Note: the original's events are lost
// (use detach + insert if you need to keep them)replaceWith() replaces the selected element with new content. It accepts a function for dynamic replacement by index. replaceAll() is the reversed form. The original element's events are destroyed. To keep handlers, use detach() + insertion instead of replace.
Batch manipulation
// SLOW: insert in a loop (reflow on each iteration)
for (var i = 0; i < 100; i++) {
$("#list").append("<li>" + i + "</li>");
}
// FAST: build a string and insert 1x
var html = "";
for (var i = 0; i < 100; i++) {
html += "<li>" + i + "</li>";
}
$("#list").html(html);
// Or: DocumentFragment
var $fragment = $(document.createDocumentFragment());
for (var i = 0; i < 100; i++) {
$fragment.append("<li>" + i + "</li>");
}
$("#list").append($fragment);Each DOM insertion causes a reflow (layout recalculation). Inserting 100 elements in a loop = 100 reflows. Building an HTML string and inserting once is much faster. DocumentFragment groups elements outside the DOM and inserts them in a batch. For large lists, prefer .html() with a complete string.
Traversing
parent() and parents()
// parent(): direct parent (1 level)
$("li").parent() // the <ul> or <ol>
// parents(): ALL ancestors
$("a").parents() // div, body, html...
// parents() with a filter:
$("a").parents("form") // only <form> ancestors
$("a").parents(".card") // first .card above
// closest(): goes up until found (includes self)
$("a").closest(".card") // the nearest .card
// closest starts at this; parents starts at the parentparent() returns the direct parent. parents() goes up to <html> (all ancestors). closest() goes up and returns the first that matches (includes the element itself). closest() is ideal for delegation and finding containers. parents() with a filter returns all that match.
filter() and not()
// filter(): keeps the ones that match
$("li").filter(".active")
$("li").filter(":even")
$("li").filter(function(i) {
return $(this).text().length > 10;
});
// not(): removes the ones that match (inverse)
$("li").not(".done")
$("li").not(":first")
$("input").not(":disabled")
// is(): checks (returns boolean)
if ($("#box").is(":visible")) { /* ... */ }
if ($(this).is(".active")) { /* ... */ }filter() reduces the collection to those that match. not() is the inverse — removes those that match. Both accept a selector, function or element. is() returns a boolean (does not filter, only checks). filter(fn) allows arbitrary logic. is() is ideal in if conditions.
closest() in practice
// Find the container from a button:
$(".btn-delete").on("click", function() {
var $card = $(this).closest(".card");
$card.fadeOut(function() { $(this).remove(); });
});
// In tables:
$("td a").on("click", function() {
var $line = $(this).closest("tr");
var id = $line.data("id");
});
// In forms:
$("input").on("invalid", function() {
$(this).closest(".form-group").addClass("error");
});
// closest vs parents:
// closest → first match (goes up)
// parents → all matchesclosest() is the most used method in delegation and handlers. It goes up the tree until it finds the first match (includes itself). Ideal to find the relevant "container" from the clicked element. More efficient than parents().first(). Common pattern: $(this).closest(".card").
children() and find()
// children(): direct children (1 level)
$("ul").children() // all direct <li>
$("ul").children(".active") // only li with the active class
// find(): descendants (any level)
$("ul").find("a") // all links inside
$("#form").find("input") // all inputs
// Difference:
// children → only 1 level below
// find → any depth
// children("*") = all children
$("#box").children().length; // how many childrenchildren() returns only direct children (1 level). find() searches at any depth. Both accept an optional filter. find() is used more (more flexible). children() is faster when you only need the first level. Without arguments, they return all descendants/children.
has() and is()
// has(): keeps elements that CONTAIN the selector
$("li").has("ul") // li that have sub-lists
$("div").has("img") // divs with images
$("td").has("a.link") // cells with links
// is(): boolean test
$("#form input").is(":focus") // any focused?
$(".card").is(":visible") // any visible?
$(this).is("a[href^='http']") // is it an external link?
// Combine:
$("li").has("> ul").addClass("tem-submenu");has() filters elements that contain matching descendants (does not return the descendants). is() tests whether any element of the collection matches (returns true/false). has("> ul") checks direct children. Both useful for conditional logic and classifying elements.
index() — element position
// Position among siblings:
$("li").click(function() {
var pos = $(this).index(); // 0-based among siblings
console.log("Item " + pos);
});
// Position in a collection:
var $items = $(".card");
$items.click(function() {
var i = $items.index(this);
console.log("Card " + i + " de " + $items.length);
});
// Position of a selector:
var pos = $("li").index("#special");index() without arguments returns the position among siblings (zero-based). With an element/DOM the argument, it returns the position in the collection. With a selector, it returns the position of the first match. Useful for tabs, sliders and navigation. Returning -1 means not found.
siblings() and siblings
// siblings(): all siblings
$("li.active").siblings() // other li
$("li.active").siblings(".done") // siblings with the class
// next(): next sibling (1)
$("li.active").next()
// prev(): previous sibling (1)
$("li.active").prev()
// nextAll() / prevAll():
$("li.active").nextAll() // all after
$("li.active").prevAll() // all before
// nextUntil() / prevUntil():
$("li.active").nextUntil(".end") // until .end is foundsiblings() returns all siblings (excludes itself). next()/prev() return the immediately following/previous sibling. nextAll()/prevAll() return all in one direction. nextUntil() stops when it finds the selector. All accept an optional filter. Useful for navigating lists and tabs.
add() and addBack()
// add(): combines selections
$("h1").add("h2").add("h3").css("color", "navy");
$("p").add(".grade").addClass("text");
// addBack(): re-adds the previous selection
$("ul").find("li") // only li
.addClass("item")
.addBack() // ul + li
.css("border", "1px solid #ccc");
// Without addBack (repeat the selector):
var $ul = $("ul");
$ul.find("li").addClass("item");
$ul.css("border", "1px solid #ccc");add() combines multiple selections into a single jQuery object. addBack() re-adds the elements from the previous selection (before the find()/filter()). addBack(selector) re-adds only those that match. Avoids repeating selectors in operations that affect parents and children.
Table navigation
// Common pattern: actions on table rows
$("#table").on("click", ".btn-edit", function() {
var $tr = $(this).closest("tr");
var id = $tr.data("id");
var name = $tr.find("td").eq(1).text();
var email = $tr.find("td").eq(2).text();
abrirModal(id, name, email);
});
// Zebra striping:
$("#table tr:even").addClass("zebra");
// Highlight row on hover:
$("#table").on("mouseenter", "tr", function() {
$(this).addClass("hover");
}).on("mouseleave", "tr", function() {
$(this).removeClass("hover");
});Typical pattern: closest("tr") for the row, find("td").eq(n) for cells. data-id on the <tr> stores the identifier. :even to zebra-stripe. Delegation with on() for buttons inside cells. This pattern applies to any repetitive structure (cards, lists, grids).
first(), last() and eq()
var $items = $("li");
// first(): first of the collection
$items.first().addClass("highlight");
// last(): last of the collection
$items.last().addClass("end");
// eq(n): specific index (zero-based)
$items.eq(0).css("color", "red"); // first
$items.eq(2).css("color", "blue"); // third
$items.eq(-1).css("color", "green"); // last
// slice(start, end):
$items.slice(1, 4).addClass("middle"); // indices 1,2,3Position methods on the jQuery collection. eq(n) is zero-based and accepts negatives (-1 = last). slice() works like Array.slice (end exclusive). All return a new jQuery object (chainable). Faster than the pseudo-selectors :first, :last, :eq().
contents()
// contents(): children including text and comments
$("#box").contents()
// Difference from children():
// children() → only elements
// contents() → elements + text nodes + comments
// Manipulate text inside an element:
$("#paragraph").contents().filter(function() {
return this.nodeType === 3; // text node
}).wrap("<strong></strong>");
// Useful for iframes:
$("#frame").contents().find("body").css("font", "16px");contents() returns all child nodes: elements, text and comments. children() returns only elements. nodeType === 3 identifies text nodes. Useful to manipulate inline text without affecting tags. contents() on iframes gives access to the internal document (same origin).
Attributes and Data
attr() — HTML attributes
// Read an attribute:
var href = $("a").attr("href");
var alt = $("img").attr("alt");
// Set:
$("a").attr("href", "/new-page");
$("img").attr("alt", "Description da image");
// Multiple at once:
$("a").attr({
href: "/link",
target: "_blank",
rel: "noopener"
});
// With a function:
$("li").attr("data-index", function(i) {
return i;
});attr() reads/sets HTML attributes (what is in the markup). Without an argument it returns the first element's value. With an argument it sets on all selected. Accepts an object for multiple attributes. Returns undefined if the attribute does not exist. For boolean values (checked, disabled), prefer prop().
hasClass()
// Check whether it has a class:
if ($("#menu").hasClass("open")) {
fecharMenu();
} else {
abrirMenu();
}
// Equivalent with toggleClass:
$("#menu").toggleClass("open");
// On collections (any element):
if ($(".card").hasClass("seleccionado")) {
// at least ONE card has the class
}
// Native contains() (alternative):
this.classList.contains("active");hasClass() returns true if any element of the collection has the class. It does not accept multiple classes. Native equivalent: classList.contains(). Useful for if conditions. To toggle without checking, use toggleClass() directly (more concise).
Manipulate multiple attributes
// Pattern: update several attributes
function actualizarLink($el, data) {
$el.attr({
href: data.url,
title: data.title,
"aria-label": data.title,
target: data.external ? "_blank" : "_self"
});
}
// Conditional attributes:
$("a").each(function() {
var $a = $(this);
if ($a.attr("href").startsWith("http")) {
$a.attr({ target: "_blank", rel: "noopener" });
}
});
// Remove in bulk:
$(".temp").removeAttr("style title data-debug");attr({}) with an object sets multiple attributes in one call (more readable). Hyphenated attributes need quotes ("aria-label"). Dynamic values with a ternary. removeAttr() accepts multiple separated by spaces. Pattern: group related attributes into a single call for clarity.
removeAttr()
// Remove an attribute:
$("input").removeAttr("disabled");
$("img").removeAttr("width height"); // multiple
// Example: enable a field
$("#field").removeAttr("readonly");
// Difference from attr("x", ""):
// removeAttr → the attribute disappears from the DOM
// attr("x","") → the attribute stays with an empty valueremoveAttr() completely removes the attribute from the element. Accepts multiple names separated by spaces. Different from setting an empty value — the attribute disappears from the markup. Useful to enable fields (disabled, readonly) or remove inline styles. For boolean properties, prop("x", false) is preferable.
val() — form values
// Read a value:
var name = $("#name").val();
var option = $("select").val();
// Set:
$("#name").val("John");
$("textarea").val("Text initial");
// Multiple select:
$("#multi").val(["op1", "op2"]); // array
var seleccionados = $("#multi").val(); // ["op1","op2"]
// Checkbox/radio (use prop):
$("#check").prop("checked", true);
// val() on a checkbox returns the value attribute
// Clear a field:
$("#search").val("");val() reads/sets the value of form fields. On a select, it returns the value of the selected option. On a select multiple, it returns/accepts an array. For checkbox/radio, use prop("checked") instead of val(). Without arguments it reads; with an argument it sets on all selected.
innerHTML vs jQuery
// jQuery:
$("#box").html("<p>New</p>");
var content = $("#box").html();
// Vanilla equivalent:
document.getElementById("box").innerHTML = "<p>New</p>";
var content = document.getElementById("box").innerHTML;
// outerHTML (element + content):
var complete = $("#box").prop("outerHTML");
// jQuery for text:
$("#box").text("Sem tags");
// Vanilla:
document.getElementById("box").textContent = "Sem tags";html() is equivalent to native innerHTML. text() is equivalent to textContent. prop("outerHTML") gets the full element (including its own tag). jQuery normalizes differences between browsers. To insert HTML from untrusted sources, sanitize first or use text() (prevents XSS).
prop() — DOM properties
// prop() for boolean states:
$("#check").prop("checked", true);
$("#field").prop("disabled", true);
$("#select").prop("selectedIndex", 2);
// Read:
var marcado = $("#check").prop("checked"); // true/false
var deactivated = $("#field").prop("disabled");
// attr vs prop:
// attr("checked") → "checked" or undefined (HTML)
// prop("checked") → true or false (current state)
// Always prop for: checked, selected, disabled, readonlyprop() accesses DOM properties (current state), not the HTML attribute. For checked, disabled, selected — always use prop(). attr() returns as initial markup value; prop() returns the real-time state. Example: checkbox checked by the user → prop("checked") = true, attr("checked") may be undefined.
data() — data-attributes
// HTML: <div data-user-id="42" data-name="Anna">
// Read (automatic camelCase):
$("#div").data("user-id"); // 42 (number!)
$("#div").data("userId"); // 42 (equivalent)
$("#div").data("name"); // "Anna"
// Set (only in memory, not in the HTML):
$("#div").data("temp", {x: 1});
$("#div").data("active", true);
// Read all:
var everything = $("#div").data();
// {userId: 42, name: "Anna", temp: {x:1}, active: true}
// Remove:
$("#div").removeData("temp");data() accesses data-attributes with automatic type conversion (numbers, booleans, JSON). Hyphenated names become camelCase. data(key, value) stores in jQuery memory (does not alter the HTML). Accepts objects and arrays. removeData() clears it. Faster than attr("data-*") for repeated reads.
State toggle pattern
// Menu toggle:
$("#btn-menu").on("click", function() {
$("#menu").toggleClass("open");
$(this).toggleClass("active");
$("#menu").attr("aria-expanded",
$("#menu").hasClass("open")
);
});
// Disabled toggle:
function toggleField($field, active) {
$field.prop("disabled", !active);
$field.toggleClass("deactivated", !active);
}
// State with data:
$("#btn").on("click", function() {
var $btn = $(this);
var active = !$btn.data("active");
$btn.data("active", active);
$btn.text(active ? "ON" : "OFF");
});Common pattern: toggleClass() + prop() + data() to manage state. Sync ARIA attributes (aria-expanded) for accessibility. data() stores the logical state; classes control the visual. Helper functions (toggleField) avoid repetition. Keep state and UI in sync.
addClass() and removeClass()
// Add class(es):
$("#box").addClass("active");
$("#box").addClass("visible highlight");
// Remove:
$("#box").removeClass("active");
$("#box").removeClass(); // removes ALL
// Toggle (adds if absent, removes if present):
$("#box").toggleClass("open");
// With a condition:
$("#box").toggleClass("error", hasError);
// true → adds; false → removes
// With a function:
$("li").addClass(function(i) {
return "item-" + i;
});addClass()/removeClass() manipulate classes without affecting other existing ones. toggleClass() alternates (adds/removes). A second boolean parameter forces add or remove. Without arguments, removeClass() removes all classes. They accept multiple classes separated by spaces. Prefer classes over inline styles.
data() vs attr("data-*")
// HTML: <button data-id="5" data-config='{"a":1}'>
// data() → converts types + memory cache:
$("button").data("id"); // 5 (Number)
$("button").data("config"); // {a: 1} (Object)
// attr() → always a string from the HTML:
$("button").attr("data-id"); // "5" (String)
$("button").attr("data-config"); // '{"a":1}' (String)
// data() does not reflect changes in the HTML:
$("button").attr("data-id", "99");
$("button").data("id"); // still 5 (cache!)
$("button").attr("data-id"); // "99"
// Rule: use data() consistentlydata() converts types automatically and caches in memory. attr("data-*") always returns a string from the current HTML. Careful: after data() reads, changes to the HTML via attr() are not reflected (cache). Use one or the other consistently. data() is preferable for performance and types.
CSS and Dimensions
css() — read and set styles
// Read (returns the computed value):
var color = $("#box").css("color"); // "rgb(255, 0, 0)"
var size = $("#box").css("font-size"); // "16px"
// Set:
$("#box").css("color", "blue");
$("#box").css("font-size", "18px");
// Multiple (object, camelCase):
$("#box").css({
backgroundColor: "#f0f0f0",
border: "2px solid #333",
padding: "10px",
borderRadius: "4px"
});css() without an argument returns the computed value (not the inline one). With an argument it sets an inline style. An object uses camelCase (not hyphens). Multiple properties in one call. Numeric values without a unit assume px. Prefer addClass() over css() for reusable styles.
fadeIn() and fadeOut()
// Fade (opacity only):
$("#box").fadeIn(400);
$("#box").fadeOut(400);
$("#box").fadeToggle(400);
// Partial opacity:
$("#box").fadeTo(300, 0.5); // 50% opacity
// Callback:
$("#overlay").fadeIn(200, function() {
$("#modal").fadeIn(300);
});
// Sequence:
$("#a").fadeOut(200, function() {
$("#b").fadeIn(200);
});fadeIn()/fadeOut() animate only opacity (do not affect layout like show/hide). fadeTo() sets partial opacity without hiding. fadeToggle() alternates. They accept a duration (ms or "slow"/"fast") and a completion callback. Chain in callbacks for sequences. The element gets display:none after fadeOut.
Animation queue
// Animations chain automatically:
$("#box")
.fadeIn(300)
.animate({ left: "100px" }, 500)
.fadeOut(300);
// runs in sequence (the "fx" queue)
// queue() to inspect:
var size = $("#box").queue("fx").length;
// dequeue() to continue manually:
$("#box").queue(function(next) {
$(this).addClass("processando");
setTimeout(next, 1000); // call next() to continue
});
// Clear the queue:
$("#box").clearQueue();
$("#box").stop(true); // equivalentjQuery animations enter a queue ("fx") and run in sequence. queue(fn) adds custom steps to the queue (call next() to continue). clearQueue() removes pending ones. stop(true) clears the queue + stops the current one. For simultaneous animations, call animate() with the properties in the same object.
width() and height()
// content (no padding/border):
$("#box").width(); // 200
$("#box").height(); // 100
// Set:
$("#box").width(300);
$("#box").height("50%");
// innerWidth/Height (content + padding):
$("#box").innerWidth(); // 220 (200 + 10+10)
// outerWidth/Height (+ border):
$("#box").outerWidth(); // 224 (220 + 2+2)
// outerWidth(true) (+ margin):
$("#box").outerWidth(true); // 244 (224 + 10+10)width()/height() return the content dimensions (no padding/border/margin). innerWidth() includes padding. outerWidth() includes padding + border. outerWidth(true) also includes margin. They return numbers (no "px"). To set, they accept a number (px) or string ("50%").
slideUp() and slideDown()
// Slide (animates height):
$("#panel").slideDown(300);
$("#panel").slideUp(300);
$("#panel").slideToggle(300);
// Dropdown menu:
$("#menu-btn").on("click", function() {
$("#dropdown").slideToggle(200);
});
// Accordion:
$(".acc-header").on("click", function() {
$(this).next(".acc-body").slideToggle(300);
$(this).closest(".acc-item")
.siblings().find(".acc-body").slideUp(300);
});slideUp()/slideDown() animate the element's height (curtain effect). slideToggle() alternates. Ideal for dropdown menus, accordions and collapsible panels. The element needs overflow:hidden during the animation (jQuery applies it automatically). Callback in the second parameter.
CSS transitions vs jQuery
/* CSS (prefer for performance): */
.box {
transition: opacity 0.3s, transform 0.3s;
opacity: 1;
}
.box.hidden {
opacity: 0;
transform: translateY(-10px);
}
// jQuery only toggles the class:
$("#btn").on("click", function() {
$("#box").toggleClass("hidden");
});
// jQuery animate for what CSS cannot do:
$("#box").animate({ scrollTop: 0 }, 500);
// scroll is not animatable with a CSS transitionCSS transitions are more performant (GPU, do not block JS). Use jQuery only for toggleClass and let CSS animate. animate() for what CSS cannot do: scroll, counters, relative values. Transitions do not need a queue/stop. Rule: CSS for visuals, jQuery for logic and scroll.
position() and offset()
// position(): relative to the positioned PARENT
var pos = $("#filho").position();
pos.top; // distance to the parent's top
pos.left; // distance to the parent's left
// offset(): relative to the DOCUMENT
var off = $("#box").offset();
off.top; // distance to the page top
off.left; // distance to the page left
// Set offset (moves the element):
$("#box").offset({ top: 100, left: 50 });
// Current scroll:
$(window).scrollTop(); // vertical scroll
$(window).scrollLeft(); // horizontal scrollposition() is relative to the offset parent (nearest positioned parent). offset() is relative to the document (whole page). Both return {top, left}. offset() can set the position. For elements fixed to the viewport, combine offset() with $(window).scrollTop().
animate()
// Custom animation:
$("#box").animate({
left: "200px",
opacity: 0.5,
width: "300px"
}, 500);
// With easing and callback:
$("#box").animate(
{ top: "100px" },
800,
"swing", // or "linear"
function() { console.log("end!"); }
);
// Relative properties:
$("#box").animate({ left: "+=50" }, 300);
$("#box").animate({ opacity: "-=0.2" }, 300);
// Note: needs position:relative/absoluteanimate() animates numeric CSS properties. It does not animate colors (use jQuery UI or CSS transitions). +=/-= for relative values. Parameters: properties, duration, easing ("swing" or "linear") and callback. The element needs a defined position to animate top/left. Multiple properties animate simultaneously.
Scroll and position
// Smooth scroll to an element:
$("a[href^='#']").on("click", function(e) {
e.preventDefault();
var target = $($(this).attr("href"));
$("html, body").animate({
scrollTop: target.offset().top - 80 // header offset
}, 500);
});
// Read scroll:
$(window).scrollTop(); // current position
$(window).scrollTop(0); // go to the top
// Container scroll:
$("#panel").scrollTop(200);
// Detect end of scroll:
$(window).on("scroll", function() {
if ($(window).scrollTop() + $(window).height()
>= $(document).height() - 100) {
loadMore(); // infinite scroll
}
});scrollTop() reads/sets the scroll position. Animate $("html, body") for cross-browser smooth scroll. Subtract the fixed header height when computing the position. $(window).height() + scrollTop() vs $(document).height() to detect the page end (infinite scroll). throttle the scroll event for performance.
show(), hide() and toggle()
// Show/hide (no animation):
$("#box").show();
$("#box").hide();
$("#box").toggle(); // alternates
// With duration (becomes an animation):
$("#box").show(300); // 300ms
$("#box").hide("slow"); // 600ms
$("#box").toggle("fast"); // 200ms
// Callback on complete:
$("#box").hide(300, function() {
console.log("ocultado!");
});
// hide() = display:none (stores the original display)
// show() restores the previous displayshow()/hide() change display (no animation by default). With a duration, they animate opacity + size. toggle() alternates between show/hide. jQuery remembers the original display to restore. hide() sets display:none. Callbacks run after completion. "slow"=600ms, "fast"=200ms.
stop() and delay()
// Stop the current animation:
$("#box").stop();
// Stop and jump to the end:
$("#box").stop(true, true);
// Stop ALL in the queue:
$("#box").stop(true, false);
// Delay between animations:
$("#box")
.delay(500) // waits 500ms
.fadeIn(300)
.delay(1000) // waits 1s
.fadeOut(300);
// Classic problem: hover with a queue
$("#menu").hover(
function() { $(this).stop(true).slideDown(200); },
function() { $(this).stop(true).slideUp(200); }
);stop() interrupts the current animation. stop(true) clears the queue of pending animations. stop(true, true) jumps to the end. delay(ms) inserts a pause between queued animations. Always use stop(true) on hover to avoid animation buildup (classic jQuery bug).
Effects and Animations
Combined basic effects
// show/hide with animation:
$("#box").show(400); // appears with scale
$("#box").hide(400); // disappears with scale
$("#box").toggle(400); // alternates
// fade (opacity only):
$("#box").fadeIn(400);
$("#box").fadeOut(400);
$("#box").fadeToggle(400);
// slide (height only):
$("#box").slideDown(400);
$("#box").slideUp(400);
$("#box").slideToggle(400);
// Duration: number (ms) or string
// "slow" = 600ms, "fast" = 200msThree families of effects: show/hide (opacity + size), fade (opacity only), slide (height only). All accept a duration in ms or "slow"/"fast". The toggle in each family alternates automatically. Without a duration, show/hide is instant; fade/slide need a duration. Callback in the last parameter.
Simultaneous animations
// Simultaneous: properties in the same animate()
$("#box").animate({
opacity: 0,
left: "+=100",
height: "toggle"
}, 500);
// Multiple elements at the same time:
$(".card").each(function(i) {
$(this).delay(i * 100).fadeIn(400);
});
// cascade effect (stagger)
// Parallel with synchronization:
$("#background").animate({opacity: 0.5}, 300);
$("#text").animate({fontSize: "2em"}, 300);
// both run in parallel (different elements)Properties in the same animate() run simultaneously. Different elements animate in parallel automatically. delay(i * 100) creates a cascade effect (stagger). The queue is per element — distinct elements do not block each other. For complex sequences, use callbacks or $.when().
Simple tooltip
// Tooltip with fade:
$("[data-tooltip]").on("mouseenter", function(e) {
var text = $(this).data("tooltip");
var $tip = $('<div class="tooltip"></div>').text(text);
$("body").append($tip);
$tip.css({
top: e.pageY - 30,
left: e.pageX + 10
}).fadeIn(150);
}).on("mouseleave", function() {
$(".tooltip").fadeOut(100, function() {
$(this).remove();
});
});
// Follow the mouse:
$("[data-tooltip]").on("mousemove", function(e) {
$(".tooltip").css({ top: e.pageY - 30, left: e.pageX + 10 });
});A tooltip created dynamically with data-tooltip. Positioned with e.pageX/pageY on mouseenter. fadeIn/fadeOut for a smooth transition. Remove from the DOM after fadeOut (avoid buildup). mousemove to follow the cursor. Use text() (not html) to prevent XSS. For production, prefer dedicated libraries.
Advanced animate()
// Multiple properties:
$("#box").animate({
width: "toggle", // toggles width
opacity: "toggle", // toggles opacity
left: "200px",
fontSize: "1.5em"
}, 600);
// Relative values:
$("#box").animate({ left: "+=100", top: "-=50" }, 400);
// Step by step (step callback):
$("#barra").animate({ width: "100%" }, {
duration: 1000,
step: function(now) {
$(this).text(Math.round(now) + "%");
},
complete: function() {
$(this).text("Done!");
}
});animate() accepts "toggle", "show", "hide" the values to alternate. +=/-= for relative movement. An options object allows step (on each frame) and complete (at the end). step is useful for counters and progress bars. It does not animate colors, transforms or non-numeric properties.
Modal / Overlay
// Open modal:
function abrirModal() {
$("#overlay").fadeIn(200);
$("#modal").fadeIn(300).css("display", "flex");
}
// Close:
function fecharModal() {
$("#modal").fadeOut(200);
$("#overlay").fadeOut(300);
}
// Close with ESC or a click on the overlay:
$(document).on("keydown", function(e) {
if (e.key === "Escape") fecharModal();
});
$("#overlay").on("click", fecharModal);
// Prevent body scroll:
$("body").css("overflow", "hidden"); // open
$("body").css("overflow", ""); // closeModal pattern: overlay (dark background) + central box. fadeIn to open, fadeOut to close. Close with ESC and a click on the overlay. Block body scroll with overflow:hidden. Use a high z-index in the CSS. For accessibility, manage focus and aria-modal.
Animated counter
// Animate a number from 0 to a target:
function animarNumero($el, target, duration) {
$({ value: 0 }).animate({ value: target }, {
duration: duration || 1500,
easing: "swing",
step: function() {
$el.text(Math.floor(this.value));
},
complete: function() {
$el.text(target); // ensure the exact value
}
});
}
// Usage:
animarNumero($("#stats-users"), 15000);
animarNumero($("#stats-sales"), 892);
// With formatting:
step: function() {
$el.text(Math.floor(this.value).toLocaleString("pt-PT"));
}Trick: animate a plain object ($({value: 0})) and use step to update the text. Math.floor() avoids decimals during the animation. complete ensures the exact value at the end. toLocaleString() for thousands formatting. A popular visual effect on landing pages and dashboards.
Easing
// Built-in easing:
$("#box").animate({left: "200px"}, 500, "swing");
$("#box").animate({left: "200px"}, 500, "linear");
// swing: accelerates at the start, decelerates at the end (default)
// linear: constant speed
// With jQuery UI (more easings):
$("#box").animate({top: "100px"}, 800, "easeOutBounce");
$("#box").animate({left: "300px"}, 600, "easeInOutCubic");
$("#box").animate({width: "toggle"}, 500, "easeOutElastic");
// Set a default:
$.fx.speeds.verySlow = 1000;
$("#box").fadeIn("verySlow");Easing controls the animation's acceleration. jQuery core only has "swing" (default) and "linear". jQuery UI adds dozens (easeOutBounce, easeInOutCubic, etc.). $.fx.speeds lets you create custom named durations. For complex animations, consider CSS transitions/animations or GSAP.
Accordion
// HTML: .acc-item > .acc-header + .acc-body
$(".acc-header").on("click", function() {
var $item = $(this).closest(".acc-item");
var $body = $item.find(".acc-body");
var open = $body.is(":visible");
// Close all:
$(".acc-body").slideUp(300);
$(".acc-item").removeClass("active");
// Open the clicked one (if it was closed):
if (!open) {
$body.slideDown(300);
$item.addClass("active");
}
});
// Initialize: first one open
$(".acc-item:first .acc-body").show();
$(".acc-item:first").addClass("active");Accordion pattern: slideUp() closes all, slideDown() opens the selected one. is(":visible") checks the current state. closest() and find() for navigation. The active class styles the header. Allow closing all or always keeping one open (remove the if). Initialize the state on startup.
Image lazy load
// HTML: <img data-src="photo.jpg" class="lazy">
function lazyLoad() {
$(".lazy").each(function() {
var $img = $(this);
var top = $img.offset().top;
var scroll = $(window).scrollTop();
var height = $(window).height();
if (top < scroll + height + 200) {
$img.attr("src", $img.data("src"))
.removeAttr("data-src")
.removeClass("lazy")
.hide().fadeIn(400);
}
});
}
$(window).on("scroll", lazyLoad);
lazyLoad(); // check visible ones on load
// Note: throttle the scroll!Lazy load: an image only loads when it enters the viewport. data-src stores the real URL; src stays empty/placeholder. Check offset().top vs scrollTop() + height(). A 200px margin to preload. fadeIn for the transition. Always throttle the scroll. Today: prefer native loading="lazy" or IntersectionObserver.
Animation callbacks
// Callback on complete:
$("#box").fadeOut(300, function() {
$(this).remove(); // remove after hiding
});
// Sequence with callbacks:
$("#a").fadeOut(200, function() {
$("#b").fadeIn(200, function() {
$("#c").slideDown(200);
});
});
// Promise (jQuery 3+):
$("#box").fadeOut(300).promise().done(function() {
console.log("all animations complete");
});
// $.when for multiple:
$.when(
$("#a").fadeIn(300),
$("#b").slideDown(300)
).done(function() {
$("#c").show();
});A callback runs when the animation finishes (per element). For collections, it fires once per element. .promise().done() fires once when all finish. $.when() waits for multiple animations in parallel. Pattern: animate → callback → next action. Avoid deep nesting (callback hell).
Tabs
// HTML: .tab-btn[data-tab] + .tab-panel[id]
$(".tab-btn").on("click", function() {
var target = $(this).data("tab");
// Deactivate all:
$(".tab-btn").removeClass("activa");
$(".tab-panel").hide();
// Activate the selected one:
$(this).addClass("activa");
$("#" + target).fadeIn(200);
});
// With URL hash:
var hash = window.location.hash.slice(1);
if (hash) {
$('.tab-btn[data-tab="' + hash + '"]').click();
} else {
$(".tab-btn:first").click();
}Tabs pattern: buttons with data-tab point to panel IDs. hide() all + fadeIn() the active one. The activa class styles the button. Support the URL hash for deep-linking. Trigger click() programmatically to initialize. Alternative: CSS with :target (no JS).
AJAX
$.ajax() — the complete method
$.ajax({
url: "/api/data",
method: "GET",
dataType: "json",
data: { page: 1, limit: 20 },
headers: { "X-Token": "abc123" },
timeout: 5000,
beforeSend: function() {
$("#loading").show();
},
success: function(data, status, xhr) {
render(data);
},
error: function(xhr, status, error) {
alert("Error: " + error);
},
complete: function() {
$("#loading").hide();
}
});$.ajax() is the most complete and flexible method. method: GET, POST, PUT, DELETE. dataType: expected response type (json, html, text). data: parameters sent. Callbacks: beforeSend (before), success (success), error (failure), complete (always). The base of all jQuery AJAX shortcuts.
Send JSON
// POST with JSON:
$.ajax({
url: "/api/products",
method: "POST",
contentType: "application/json",
data: JSON.stringify({
name: "Product X",
price: 29.90,
tags: ["new", "highlight"]
}),
success: function(response) {
console.log("ID:", response.id);
}
});
// Important note:
// contentType: "application/json" → send JSON
// (default is "x-www-form-urlencoded")
// data must be JSON.stringify()
// PUT and DELETE:
$.ajax({ url: "/api/x/1", method: "PUT", ... });
$.ajax({ url: "/api/x/1", method: "DELETE", ... });To send JSON: set contentType: "application/json" and use JSON.stringify() on the data. Without this, jQuery sends it the form-encoded. method accepts PUT, DELETE, PATCH. The server must respond with JSON. For REST APIs, this is the most common pattern. Auth headers via headers: {}.
AJAX with forms
$("form").on("submit", function(e) {
e.preventDefault();
var $form = $(this);
var $btn = $form.find("[type=submit]");
$btn.prop("disabled", true).text("A send...");
$.ajax({
url: $form.attr("action"),
method: $form.attr("method"),
data: $form.serialize(),
success: function(r) {
alert("Success!");
$form[0].reset();
},
error: function(xhr) {
var errors = xhr.responseJSON.errors;
$.each(errors, function(field, msg) {
$("#" + field).after('<span class="error">' + msg + '</span>');
});
},
complete: function() {
$btn.prop("disabled", false).text("Send");
}
});
});AJAX form pattern: preventDefault(), serialize() for the data, disable the button while sending. $form.attr("action") and $form.attr("method") respect the HTML. complete re-enables the button (success or error). Map validation errors per field. $form[0].reset() clears the native form.
$.get() and $.post()
// Simple GET:
$.get("/api/users", function(data) {
console.log(data);
});
// GET with parameters:
$.get("/api/users", { active: 1 }, function(data) {
list(data);
}, "json");
// POST:
$.post("/api/users", {
name: "Anna",
email: "ana@email.com"
}, function(response) {
alert("Created: " + response.id);
}, "json");
// POST with error:
$.post("/api/login", data)
.done(function(r) { /* ok */ })
.fail(function(xhr) { /* error */ });$.get() and $.post() are simplified shortcuts. Parameters: url, data, callback, dataType. They return a jqXHR (thenable) — use .done()/.fail() instead of a callback. $.getJSON() is a shortcut for GET with dataType json. For advanced settings (headers, timeout), use $.ajax().
File upload
// HTML: <input type="file" id="file">
$("#form-upload").on("submit", function(e) {
e.preventDefault();
var formData = new FormData(this);
// or: formData.append("file", $("#file")[0].files[0]);
$.ajax({
url: "/api/upload",
method: "POST",
data: formData,
processData: false, // do NOT process the data
contentType: false, // do NOT set the content-type
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
var pct = (e.loaded / e.total) * 100;
$("#progresso").css("width", pct + "%");
};
return xhr;
},
success: function(r) { alert("Upload: " + r.url); }
});
});Upload uses native FormData. processData: false prevents jQuery from serializing. contentType: false lets the browser set multipart. xhr.upload.onprogress for a progress bar. this.files[0] accesses the input's file. Never use $.post() for uploads — you need $.ajax() with these options.
Debounce for search
// Search with debounce (waits for you to stop typing):
var timer;
$("#search").on("input", function() {
var term = $(this).val();
clearTimeout(timer);
if (term.length < 2) {
$("#results").empty();
return;
}
timer = setTimeout(function() {
$.get("/api/search", { q: term }, function(data) {
var html = data.map(function(item) {
return "<li>" + item.name + "</li>";
}).join("");
$("#results").html(html);
});
}, 300); // 300ms after the last keystroke
});
// Abort the previous request:
var xhrActual;
// xhrActual = $.get(...); xhrActual.abort();Debounce: wait N ms after the last keystroke before searching. clearTimeout cancels the previous timer on each input. A minimum of 2 characters avoids unnecessary requests. xhr.abort() cancels pending requests (avoid out-of-order responses). An essential pattern for autocomplete and real-time search.
load() — load HTML
// Load HTML directly into an element:
$("#content").load("/page.html");
// Load a fragment (selector):
$("#content").load("/page.html #section");
$("#sidebar").load("/layout.html .widget");
// With data and callback:
$("#results").load("/search", { q: "jquery" },
function(response, status, xhr) {
if (status === "error") {
$(this).html("Error: " + xhr.status);
}
}
);
// Replace vs insert:
// load() REPLACES the element's contentload() does a GET and inserts the HTML response directly into the element. With a selector after a space, it loads only a fragment of the page. The callback receives (response, status, xhr). It replaces the existing content. Ideal to load partials, templates and dynamic content without parsing JavaScript.
ajaxSetup and interceptors
// Global configuration:
$.ajaxSetup({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf"]').attr("content")
},
timeout: 10000,
dataType: "json"
});
// Intercept ALL requests:
$(document).ajaxStart(function() {
$("#spinner").show();
});
$(document).ajaxStop(function() {
$("#spinner").hide();
});
$(document).ajaxError(function(e, xhr, settings) {
if (xhr.status === 401) {
window.location = "/login";
}
console.error("AJAX error:", settings.url);
});$.ajaxSetup() sets defaults for all AJAX requests (headers, timeout). Global events: ajaxStart/ajaxStop (global spinner), ajaxError (central error handling), ajaxSuccess. Ideal for the CSRF token, loading indicators and redirect on 401. They apply to all $.ajax(), $.get(), $.post().
Infinite scroll
var page = 1;
var carregando = false;
var end = false;
$(window).on("scroll", function() {
if (carregando || end) return;
var scrollFim = $(window).scrollTop() + $(window).height();
var docAltura = $(document).height();
if (scrollFim >= docAltura - 300) {
carregando = true;
page++;
$.get("/api/posts", { page: page }, function(data) {
if (data.length === 0) {
end = true;
$("#feed").append('<p class="end">End</p>');
return;
}
data.forEach(function(post) {
$("#feed").append(renderizarPost(post));
});
carregando = false;
});
}
});Infinite scroll: detect proximity to the page end and load more. The carregando and end flags prevent duplicate requests. A 300px margin to preload. An empty response = no more data. Always throttle the scroll event for performance. Modern alternative: IntersectionObserver (no scroll listener).
Promises and $.when()
// jQuery 3+ (Promise compatible):
$.get("/api/data")
.done(function(data) { /* success */ })
.fail(function(xhr) { /* error */ })
.always(function() { /* always */ });
// then() (chainable):
$.get("/api/users")
.then(function(users) {
return $.get("/api/posts/" + users[0].id);
})
.then(function(posts) {
render(posts);
})
.catch(function(error) {
console.error(error);
});
// Multiple parallel requests:
$.when(
$.get("/api/users"),
$.get("/api/posts"),
$.get("/api/comments")
).done(function(users, posts, comments) {
// all complete
});jQuery 3+ returns compatible Promises. .done()/.fail()/.always() are the jQuery callbacks. .then() lets you chain sequential requests. $.when() waits for multiple requests in parallel. Each done argument in $.when is an array [data, status, xhr]. Prefer then/catch for modern code.
Error handling
$.ajax({ url: "/api/data" })
.done(function(data) {
render(data);
})
.fail(function(xhr, status, error) {
switch (xhr.status) {
case 400:
mostrarErros(xhr.responseJSON.errors);
break;
case 401:
redirect("/login");
break;
case 404:
alert("Recurso not found");
break;
case 422:
var errors = xhr.responseJSON;
Object.keys(errors).forEach(function(field) {
$("#" + field).addClass("error");
});
break;
case 500:
alert("Error no server");
break;
}
});xhr.status gives the HTTP status code. xhr.responseJSON is the parsed JSON response (if dataType json). status (string): "success", "error", "timeout", "parsererror". Pattern: switch by status code with specific messages. 422 for validation errors with per-field mapping. Always handle errors — never assume success.
Forms
serialize() and serializeArray()
// serialize(): query string
var data = $("form").serialize();
// "name=Anna&email=ana@mail.com&age=25"
// serializeArray(): array of objects
var arr = $("form").serializeArray();
// [{name: "name", value: "Anna"}, {name: "email", value: "ana@mail.com"}]
// Convert to an object:
var obj = {};
$.each(arr, function(i, field) {
obj[field.name] = field.value;
});
// Only specific fields:
$("#form :input:not(:disabled)").serialize();serialize() converts all form fields into a query string (ready for POST). serializeArray() returns an array of {name, value}. It includes only fields with a name that are not disabled. Checkboxes/radios only if checked. Ideal to send via AJAX. It does not include file inputs (use FormData).
Checkbox and radio
// Checkbox:
$("#terms").prop("checked"); // true/false
$("#terms").prop("checked", true); // check
$("#terms").is(":checked"); // verify
// All checked:
var marcados = $('input[name="tags"]:checked')
.map(function() { return $(this).val(); })
.get(); // ["js", "css"]
// Radio:
var option = $('input[name="type"]:checked').val();
// Check a radio:
$('input[name="type"][value="admin"]').prop("checked", true);
// Select all / deselect all:
$("#select-all").on("change", function() {
$(".checkbox-item").prop("checked", $(this).is(":checked"));
});For checkbox/radio, always use prop("checked") (not attr). :checked filters the checked ones. .map().get() extracts values the an array. Radio: :checked returns the selected one of the group. "Select all" pattern: propagate the master checkbox's state to all items.
Visual state feedback
// Button states:
function setButtonState($btn, state) {
$btn.prop("disabled", state === "loading");
$btn.html({
idle: "Send",
loading: '<span class="spinner"></span> A send...',
success: "✓ Shipped!",
error: "✗ Error — Try again"
}[state]);
$btn.attr("class", "btn btn-" + state);
}
// Usage:
setButtonState($("#btn"), "loading");
$.post("/api/send", data)
.done(function() { setButtonState($("#btn"), "success"); })
.fail(function() { setButtonState($("#btn"), "error"); });Buttons with states: idle, loading, success, error. prop("disabled") prevents a double click. A mapping object for the HTML per state. A CSS class per state for styling. An inline spinner during loading. Clear visual feedback improves UX. Revert to idle after a timeout in case of an error.
Basic validation
$("form").on("submit", function(e) {
var errors = [];
var name = $("#name").val().trim();
if (name.length < 3) {
errors.push("Name: minimum 3 characters");
$("#name").addClass("error");
}
var email = $("#email").val();
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
errors.push("Email invalid");
$("#email").addClass("error");
}
if (errors.length > 0) {
e.preventDefault();
$("#errors").html(errors.map(function(e) {
return "<li>" + e + "</li>";
}).join(""));
}
});Client-side validation before the submit. trim() removes spaces. A regex for the email. addClass("error") highlights invalid fields. preventDefault() blocks submission if there are errors. Show messages in a container. Complement (do not replace) server-side validation. Clear errors on the field's input.
Dynamic select
// Fill a select via AJAX:
$("#country").on("change", function() {
var paisId = $(this).val();
var $city = $("#city");
$city.prop("disabled", true).html("<option>A load...</option>");
$.get("/api/cities", { country: paisId }, function(data) {
var options = '<option value="">Select...</option>';
data.forEach(function(c) {
options += '<option value="' + c.id + '">' + c.name + '</option>';
});
$city.html(options).prop("disabled", false);
});
});
// Read the selected one:
var value = $("#city").val();
var text = $("#city option:selected").text();Dependent selects: changing one loads the other's options via AJAX. Disable during loading. Rebuild the <option> with the response. val() returns the value; option:selected + text() for the visible text. Always include an initial empty option. Clear the dependent select when AS parent changes.
Simple autocomplete
var $input = $("#search");
var $list = $("#sugestoes");
var timer;
$input.on("input", function() {
var term = $(this).val().trim();
clearTimeout(timer);
if (term.length < 2) { $list.hide(); return; }
timer = setTimeout(function() {
$.get("/api/sugestoes", { q: term }, function(data) {
var html = data.map(function(item) {
return '<li data-id="' + item.id + '">' + item.name + '</li>';
}).join("");
$list.html(html).show();
});
}, 250);
});
// Select a suggestion (delegation):
$list.on("click", "li", function() {
$input.val($(this).text());
$input.data("id", $(this).data("id"));
$list.hide();
});
// Close on clicking outside:
$(document).on("click", function(e) {
if (!$(e.target).closest("#search, #sugestoes").length) {
$list.hide();
}
});Autocomplete: debounce + AJAX + a suggestions list. data-id stores the selected ID. Delegation for clicks on dynamic items. Close on clicking outside with closest(). A minimum of 2 characters. For accessibility: aria-autocomplete, keyboard navigation. For production, use libraries (Typeahead, Select2).
Real-time validation
// Validate when leaving the field:
$("#email").on("blur", function() {
var $field = $(this);
var valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test($field.val());
$field.toggleClass("error", !valid);
$field.next(".msg-error").toggle(!valid);
});
// Clear the error while typing:
$(".field").on("input", function() {
$(this).removeClass("error");
$(this).next(".msg-error").hide();
});
// Validate password strength:
$("#pass").on("input", function() {
var forca = calcularForca($(this).val());
$("#forca").css("width", forca + "%");
});Validating on blur (when leaving the field) is less intrusive than on every keystroke. toggleClass(class, boolean) adds/removes based on a condition. Clear the error on input for immediate feedback. Adjacent error messages (.next(".msg-error")). A strength indicator for passwords. A balance between UX and strict validation.
Input mask
// Simple phone mask:
$("#phone").on("input", function() {
var v = $(this).val().replace(/\D/g, "");
if (v.length > 9) v = v.slice(0, 9);
if (v.length > 6) {
v = v.replace(/(\d{3})(\d{3})(\d+)/, "$1 $2 $3");
} else if (v.length > 3) {
v = v.replace(/(\d{3})(\d+)/, "$1 $2");
}
$(this).val(v);
});
// NIF mask (9 digits):
$("#nif").on("input", function() {
$(this).val($(this).val().replace(/\D/g, "").slice(0, 9));
});
// Format on leaving:
$("#price").on("blur", function() {
var v = parseFloat($(this).val()) || 0;
$(this).val(v.toFixed(2));
});Masks format the input in real time. replace(/\D/g, "") removes non-digits. slice() limits the length. A regex with groups to insert separators. Format on blur for monetary values. For complex masks, use plugins (jquery.mask, inputmask). Always validate on the server too.
Basic drag and drop
// Reorder a list (no plugin):
var $arrastado = null;
$("#list li").on("dragstart", function() {
$arrastado = $(this);
$(this).addClass("arrastando");
});
$("#list li").on("dragend", function() {
$(this).removeClass("arrastando");
$arrastado = null;
});
$("#list li").on("dragover", function(e) {
e.preventDefault();
});
$("#list li").on("drop", function() {
if ($arrastado && $arrastado[0] !== this) {
$(this).before($arrastado);
// send the new order to the server:
var order = $("#list li").map(function() {
return $(this).data("id");
}).get();
$.post("/api/sort", { order: order });
}
});Native HTML5 drag and drop with jQuery. dragstart/dragend on the dragged one. dragover + preventDefault() to allow the drop. drop repositions with before(). map().get() extracts the new order. For full functionality, use jQuery UI Sortable. HTML: draggable="true" on the items.
Select and manipulate fields
// All fields of a form:
$("#form :input") // input, select, textarea, button
// By type:
$("#form input:text") // type=text
$("#form input:password")
$("#form :checkbox")
$("#form :radio")
$("#form select")
$("#form textarea")
// Clear all:
$("#form")[0].reset();
// or:
$("#form :input").val("").prop("checked", false);
// Disable/enable all:
$("#form :input").prop("disabled", true);
$("#form :input").prop("disabled", false);:input selects all fields (input, select, textarea, button). Filters by type: :text, :checkbox, :radio. Native reset() restores initial values. prop("disabled") in bulk to lock forms during processing. val("") clears text; prop("checked", false) unchecks.
Multi-step form
var passoActual = 1;
var totalPassos = $(".step").length;
function mostrarPasso(n) {
$(".step").hide();
$(".step").eq(n - 1).fadeIn(300);
$("#progresso").text("Passo " + n + " de " + totalPassos);
$("#btn-previous").toggle(n > 1);
$("#btn-next").toggle(n < totalPassos);
$("#btn-submit").toggle(n === totalPassos);
}
$("#btn-next").on("click", function() {
if (validarPasso(passoActual)) {
passoActual++;
mostrarPasso(passoActual);
}
});
$("#btn-previous").on("click", function() {
passoActual--;
mostrarPasso(passoActual);
});
mostrarPasso(1);A form in steps: each .step is a section. eq(n-1) shows the current step. fadeIn for the transition. Previous/next buttons with conditional toggle(). Validate each step before advancing. A progress bar with text or percentage. Submit only on the last step.
Tips and Good Practices
Selector caching
// BAD: selects on each use
$("#menu").addClass("open");
$("#menu").find("li").show();
$("#menu").css("opacity", 1);
// GOOD: cache in a variable
var $menu = $("#menu");
$menu.addClass("open");
$menu.find("li").show();
$menu.css("opacity", 1);
// Convention: $ prefix for jQuery objects
var $list = $("#list");
var $items = $list.find("li");
var $btn = $(".btn-submit");
// Re-select only if the DOM changedEach $() traverses the DOM — avoid repetitions. Store in a variable with a $ prefix (convention). Reuse it for multiple operations. Re-select only if the DOM was modified. find() on the cache is faster than a new global selector. Significant impact in loops and frequent handlers.
Module pattern (IIFE)
// IIFE: Immediately Invoked Function Expression
(function($) {
"use strict";
var config = { speed: 300 };
function init() {
ligarEventos();
loadData();
}
function ligarEventos() {
$("#btn").on("click", handler);
}
function handler() {
$("#panel").slideToggle(config.speed);
}
function loadData() {
$.get("/api/data", render);
}
function render(data) { /* ... */ }
// Start when the DOM is ready:
$(init);
})(jQuery);An IIFE creates a private scope — variables do not pollute the global one. Passing jQuery the a parameter lets you use $ safely (noConflict mode). "use strict" enables strict mode. Private functions are inaccessible from outside. $(init) starts when the DOM is ready. A classic organization pattern before ES6 modules.
jQuery 3.x and migration
// Removed in jQuery 3:
// .load(), .unload(), .error() (event shortcuts)
// → use .on("load", fn)
// .bind()/.live()/.delegate() (deprecated)
// → use .on()
// $.parseJSON() → JSON.parse()
// $.trim() → String.prototype.trim()
// $.type() → typeof / instanceof
// New in jQuery 3:
// .addClass() accepts a function
// SVG support
// requestAnimationFrame for animations
// Compatible Promises (then/catch)
// Migration plugin:
// jquery-migrate (shows warnings)jQuery 3 removed deprecated methods: event shortcuts, .bind(), .live(). Replace them with .on(). Utilities like $.trim() have native equivalents. jQuery 3 uses requestAnimationFrame (smoother animations). Standard-compatible Promises. jquery-migrate helps with the transition (shows warnings in the console).
Delegation vs direct binding
// Direct: only existing elements
$("li").on("click", fn);
// 100 li = 100 handlers in memory
// Delegation: 1 handler on the parent
$("#list").on("click", "li", fn);
// 1 handler, works with future li
// When to use delegation:
// - Dynamic elements (AJAX)
// - Many elements (performance)
// - Lists, tables, grids
// When to use direct:
// - Static and few elements
// - Events that do not bubble (focus, blur)
// → use focusin/focusout for delegationDelegation: 1 handler on the parent vs N handlers on the children. Less memory, works with future elements. Mandatory for dynamic content (AJAX). focus/blur do not bubble — use focusin/focusout for delegation. For few static elements, direct binding is acceptable. Prefer delegation by default.
noConflict()
// If another library uses $ (Prototype, etc.):
var jq = jQuery.noConflict();
jq("#box").hide();
// Or IIFE with jQuery:
(function($) {
// $ is jQuery in here
$("#box").hide();
})(jQuery);
// Release $ AND jQuery:
var jq = jQuery.noConflict(true);
// Check availability:
if (typeof jQuery !== "undefined") {
(function($) {
// safe jQuery code
})(jQuery);
}noConflict() releases the $ variable for other libraries. noConflict(true) also releases jQuery. The IIFE pattern with (jQuery) lets you use $ internally without conflict. Check typeof jQuery before using (conditional scripts). WordPress uses noConflict by default — always IIFE or jQuery().
jQuery vs modern Vanilla JS
// jQuery → Vanilla equivalent:
$("#id") → document.getElementById("id")
$(".class") → document.querySelectorAll(".class")
$el.addClass("x") → el.classList.add("x")
$el.attr("href") → el.getAttribute("href")
$el.on("click") → el.addEventListener("click")
$el.html("<p>") → el.innerHTML = "<p>"
$.ajax() → fetch()
$el.fadeIn() → el.animate([{opacity:0},{opacity:1}])
// jQuery still useful for:
// - Support for old browsers (IE)
// - Plugin ecosystem
// - Legacy code
// - Fast prototypingModern Vanilla JS covers almost everything: querySelector, classList, fetch, Web Animations API. jQuery is still relevant for IE11, plugins and legacy code. fetch() replaces $.ajax() (but without IE). For new projects without IE, vanilla or frameworks are enough. jQuery is not dead — but it is not mandatory.
Avoid memory leaks
// BAD: remove without cleaning events
$("#widget").remove(); // remove() cleans up (ok)
// BAD: innerHTML does not clean jQuery events
$("#container").html(""); // ok (jQuery cleans up)
document.getElementById("c").innerHTML = ""; // LEAK!
// GOOD: clean up before removing
$("#widget").off().removeData().remove();
// When destroying components:
function destruirModal() {
$("#modal").off(); // events
$("#modal").removeData(); // data
$("#modal").remove(); // DOM
$(document).off("keydown.modal"); // namespace
}
// SPA: clean up when changing "page"Memory leaks: orphaned events/data when the DOM is removed without jQuery. jQuery's remove() and html() clean up automatically. Native innerHTML does NOT clean up. off() + removeData() before removing for safety. Namespaces ease selective cleanup. Critical in SPAs and components that create/destroy frequently.
jQuery plugins
// Create a plugin:
$.fn.highlight = function(options) {
var settings = $.extend({
color: "yellow",
bold: true
}, options);
return this.each(function() {
$(this).css({
backgroundColor: settings.color,
fontWeight: settings.bold ? "bold" : "normal"
});
});
};
// Usage:
$("p").highlight();
$("p").highlight({ color: "#ff0", bold: false });
// Rules:
// 1. Return this.each() (chaining)
// 2. $.extend for defaults + options
// 3. $.fn prefix for instance methodsPlugins extend $.fn (the jQuery prototype). return this.each() keeps the chaining. $.extend() merges defaults with the user's options. this inside the plugin is the jQuery object (not DOM). Accept an options object for flexibility. Popular plugins: Slick, Select2, DataTables, Magnific Popup.
Performance checklist
// 1. Cache selectors
var $el = $("#box"); // do not repeat $()
// 2. Delegation instead of N handlers
$("#list").on("click", "li", fn);
// 3. Batch DOM (1 insertion vs loop)
var html = items.map(render).join("");
$("#list").html(html);
// 4. Throttle/debounce on scroll/resize
$(window).on("scroll", throttle(fn, 100));
// 5. Specific selectors
$("#form").find("input") // fast
$("form input") // slower
// 6. Avoid layout thrashing
var w = $el.width(); // read
$el.width(w + 10); // write (1x)
// 7. Remove what you do not use
$el.off().removeData().remove();A performance summary: cache, delegation, batch DOM, throttle, specific selectors. Layout thrashing: alternating reading/writing of dimensions causes multiple reflows — group reads and writes. find() with a context is faster than a global selector. Clear events/data when removing. Tools: the Chrome DevTools Performance tab to identify bottlenecks.
Throttle and debounce
// Debounce: waits for it to stop (search)
function debounce(fn, delay) {
var timer;
return function() {
var ctx = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(ctx, args);
}, delay);
};
}
$(window).on("resize", debounce(recalculate, 250));
// Throttle: at most 1x per interval (scroll)
function throttle(fn, limit) {
var last = 0;
return function() {
var now = Date.now();
if (now - last >= limit) {
last = now;
fn.apply(this, arguments);
}
};
}
$(window).on("scroll", throttle(checkPosition, 100));Debounce: runs after N ms of inactivity (search, resize). Throttle: at most 1 execution per interval (scroll, mousemove). Without these, events fire hundreds of times/second. apply(ctx, args) preserves the context. Essential for performance on high-frequency events. Libraries: lodash has both.
$.extend() and $.each()
// $.extend(): object merge
var defaults = { color: "blue", size: 12, active: true };
var options = { color: "red", size: 16 };
var final = $.extend({}, defaults, options);
// { color: "red", size: 16, active: true }
// Deep merge (nested):
$.extend(true, {}, obj1, obj2);
// $.each(): iterate arrays/objects
$.each([10, 20, 30], function(i, value) {
console.log(i, value);
});
$.each({ name: "Anna", age: 25 }, function(key, value) {
console.log(key + ": " + value);
});
// Note: $.each ≠ .each() (collection method)$.extend() merges objects (the first is the target). {} the the first one avoids mutating defaults. true for a deep merge (nested objects). $.each() iterates arrays (i, value) and objects (key, value). Different from .each() which is a jQuery collection method. Both are static utilities ($.).