jQuery Cheatsheet - jQuery API & DOM Manipulation Reference
This reference is for developers who maintain older codebases or browser extensions still built on jQuery, covering the API that lives in every such file: selectors, reading and writing DOM content and attributes, class toggling, event binding and delegation, Ajax shorthand, and simple animations. Unlike a flat jQuery API dump, entries are grouped by the interaction they perform — find elements, manipulate them, respond to events, or fetch data. After reading you should be able to chain a selector into DOM edits, delegate events to stay fast on dynamic lists, and replace a page refresh with an Ajax request.
Typical Use Case
For developers maintaining legacy front-end pages: jQuery survives in old projects without a build step, in template-generated admin panels and in WordPress themes, where it cannot be removed but does not deserve a framework either. The sheet gathers what recurs during maintenance — children versus find, choosing between class, attribute, data and value accessors, event delegation for nodes inserted at runtime, Ajax with global header injection and Promises, and animation selection. The pitfall group covers details that keep costing time.
Selectors 10
$("div") $(".class")$("#id")$("div.class")$("div > p")$("div p")$(":input")$(":checkbox")$("div:first")$("li:eq(2)")DOM Manipulation 10
$("#box").html()$("#box").html("<p>content</p>")$("#box").text()$("#box").val()$("#box").attr("data-id")$("#box").attr("data-id", "123")$("#box").addClass("active")$("#box").removeClass("active")$("#box").toggleClass("active")$("<div>").appendTo("body")Event Binding 8
$("#btn").click(fn)$("#btn").on("click", fn)$("#btn").off("click")$(document).on("click", ".btn", fn)$("input").change(fn)$("form").submit(fn)$(document).ready(fn)$(fn)Ajax Requests 5
$.get("/api/data", fn)$.post("/api/data", { key: "value" }, fn)$.getJSON("/api/data", fn)$.ajax({ url, method, data, success })$.ajaxSetup({ headers: { "X-Token": token } })Animations & Effects 8
$("#box").show()$("#box").hide()$("#box").toggle()$("#box").fadeIn()$("#box").fadeOut()$("#box").slideDown()$("#box").slideUp()$("#box").animate({ left: "200px" }, 500)Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
$("div") | Tag selector, selects all divs | $("div") |
$(".class") | Class selector, selects elements with that class name | $(".item") |
$("#id") | ID selector | $("#box") |
$("div > p") | Child selector, matches only direct child p elements | $("div > p") |
$("div p") | Descendant selector, matches p descendants at any level | $("div p") |
$(":input") | Matches all form elements | $(":input") |
$(":checkbox") | Matches all checkboxes | $(":checkbox") |
$("div:first") | Matches only the first div in the matched set | $("div:first") |
$("li:eq(2)") | Matches the element at index 2 (indexing starts at 0) | $("li:eq(2)") |
.children(sel) | Takes the direct children that satisfy the selector | $("#box").children("li") |
.find(sel) | Searches downward for matching elements among all descendants | $("#box").find("li") |
.hasClass(name) | Checks whether it has the given class name, returns a boolean | $("#box").hasClass("active") |
.data("key") | Reads the data-key stored on the element | $("#box").data("key") |
.attr("data-id") | Read/write an HTML attribute | $("#box").attr("data-id", "123") |
.html() / .html(str) | Read/write innerHTML wholesale; replacing rebuilds the child nodes | $("#box").html("<p>content</p>") |
.text() | Read/write plain text without HTML escaping | $("#box").text() |
.val() | Read/write the current value of a form control | $("#box").val() |
.addClass/.removeClass/.toggleClass | Add / remove / toggle a class name | $("#box").toggleClass("active") |
$("<div>").appendTo("body") | Create a new element and insert it at the given position | $("<div>").appendTo("body") |
.on(event, sel, fn) | Event delegation, matching events that bubble up from descendants | $(document).on("click", ".btn", fn) |
.off(event) | Unbind the event | $("#btn").off("click") |
$(document).ready(fn) | Run after the DOM has finished loading | $(document).ready(fn) |
$.get / $.post / $.getJSON | Shortcuts for GET, POST, and fetching JSON | $.get("/api/data", fn) |
$.ajax({ url, method, data, success }) | Full Ajax call; you can specify the method and data | $.ajax({ url, method, data, success }) |
$.ajaxSetup({ headers }) | Set headers globally for all Ajax requests | $.ajaxSetup({ headers: { "X-Token": token } }) |
.show/.hide/.toggle | Show, hide, or toggle visibility | $("#box").toggle() |
.fadeIn/.fadeOut | Fade in and fade out | $("#box").fadeOut() |
.slideDown/.slideUp | Slide down to show, slide up to hide | $("#box").slideDown() |
.animate(props, ms) | Custom property animation | $("#box").animate({ left: "200px" }, 500) |
Common pitfalls
SymptomAfter refreshing a container locally with .html(), all click events bound to elements inside the container stop working.
Cause.html() replaces innerHTML wholesale; the old child nodes are destroyed and the handlers bound to them are lost with them.
FixSwitch to event delegation by attaching the handler to a stable parent: $(document).on("click", ".btn", fn), so it also works for newly inserted nodes.
Symptom$("li:eq(2)") does not return the expected third element.
Cause:eq() is 0-indexed, so :eq(2) is the third; but if the selector is preceded by a tag filter, the index is relative to the filtered set rather than all nodes.
FixUse .eq(2) to pick the third item from an already-filtered set, or .slice(0, 3) to take the first three, avoiding the :first/:eq semantic confusion.
Symptom$("div:first") was expected to select the first div inside every container, but it only matches one element.
Cause:first is a positional pseudo-class that takes only the first of the entire matched set; "the first inside each parent" should use :first-child or .eq(0) per group.
FixSwitch to the CSS structural selector $("div > :first-child"), or use .children().first() on each container individually.
SymptomThe page has several duplicate ids; $("#box") can only operate on one of them, and no style change takes effect.
CauseAn id must be globally unique in HTML; duplicate ids are invalid structure, and jQuery's ID selector goes through getElementById and returns only the first.
FixReplace the duplicate ids with a class and target precisely with $(".box").eq(n), or use $(".box").filter(":nth-of-type(n)").
SymptomAfter concatenating user input directly into .html(), script tags appear and execute on the page.
Cause.html() parses and executes HTML content, so unfiltered input becomes an XSS injection point.
FixAlways use .text() to insert plain text; when you really need to insert HTML, filter first before concatenating—never hand request parameters straight to .html().
SymptomSeveral Ajax requests fire at once, and a later-returning old request overwrites the new data, making the interface jump back.
CauseConcurrent requests had no ordering control, and response arrival order is not guaranteed to match request order.
FixIn the $.ajax success callback, check whether the current page number/keyword still matches the one at send time and discard the response if not; or debounce input in the search box.
SymptomA should-style assertion raises "Cannot read property should of null" when the value is null.
CauseAccessing a property of null or undefined throws in JS first, so the assertion never gets a chance to run.
FixSwitch to the expect style: expect(value).to.not.be.null, so the assertion can safely handle the empty value before the argument is evaluated.
Troubleshooting
1Confirm how many elements the selector actually matches
console.log($("li:eq(2)").length)An output of 1 means the selector hit a single element; if you expect several, first print $('.selector').length to confirm the size of the base set.
2Confirm whether the event handler is really attached
console.log($("#btn").data("events"))An output of undefined means no event is bound; check first whether the selector hits the target element.
3Check whether an element has leftover duplicate bindings
$("#btn").off("click").on("click", fn)off then on removes duplicate bindings; if the behavior is then normal, the original problem was the same event bound multiple times.
4Add an auth header uniformly to all Ajax requests
$.ajaxSetup({ headers: { "X-Token": token } })Run this once before making any request; every request the server receives will carry that header.
5Observe the request and response actually sent
$.ajax({ url: "/api/data", method: "GET", success: console.log })Printing the response body in success tells you whether the problem is on the server response side or the front-end parsing side.
6Confirm whether you are reading/writing a value or text
console.log($("#box").val(), $("#box").text())Use .val() for form controls and .text() for plain text nodes; printing both quickly tells you which to use.
Command Examples
Event delegation for list rows inserted later
$(document).ready(function () {
$(document).on("click", ".row .del", function (e) {
e.preventDefault()
$(this).closest(".row").remove()
})
$("#box").html('<div class="row"><span class="del">x</span></div>')
})Handlers bound straight to .del are lost when html() rebuilds the markup, so clicks silently do nothing. Delegating to document binds once and keeps working for nodes added later.
Attach a token header globally, then POST a form payload
$.ajaxSetup({ headers: { "X-Token": token } })
$("form").submit(function (e) {
e.preventDefault()
$.post("/api/data", { key: "value" }, function (res) {
$("#box").text("saved: " + res.id)
})
})ajaxSetup centralizes the auth header so no individual call has to repeat it. Using text() rather than html() in the callback keeps the response from being parsed as markup.
Toggle a state class and attach data for the handler
$("#box").attr("data-id", "123")
$("#box").toggleClass("active")
$("#box").on("click", function () {
var id = $(this).data("id")
$.getJSON("/api/item/" + id, function (data) {
$(this).text(data.title)
}.bind(this))
})data("id") reads jQuery-cached data-* values, which come from the same attribute attr("data-id") writes but travel a different path. Attributes added dynamically outside HTML5 markup stay consistent only when read through attr.
Chained selection: scope to a container, then test attributes
if ($("#box").hasClass("active")) {
$("#box").find("li:eq(2)").addClass("current")
}
$("#box").children("li:first").text("first item")find scopes traversal to the container so page-wide li elements are never caught by accident. Checking hasClass first skips the whole DOM walk on the common case.
Common Pitfalls
- $(selector) searches the whole document. Writing $("li:eq(2)") picks the third li on the page, not the third inside a container, so results shift whenever another module adds rows. Use $("#box").find("li").eq(2).
- html("<p>…</p>") replaces child nodes wholesale and takes their handlers with them. After a list re-render, clicks do nothing, and the cause is here rather than in the event code.
- The .click(), .change(), and .submit() shortcuts are deprecated in jQuery 3.x and warn in the console from 3.5 onward. A team-wide 3.x upgrade needs a full pass to .on(...).
- Concatenating API or user input into .html() is an XSS hole: a single tampered response runs script in every user session. Use .text() for anything that is only text.
- A $.getJSON callback fires only on success, so failures are ignored by default: on a 500 the page neither errors nor updates. Add a $.ajax({ error }) branch or .fail.
- Writing $(".item").length or $(".item").eq(i) inside a loop re-queries the document every pass and can lock the main thread on long lists. Cache the collection in a variable and walk it with .each.
Tips
- Event delegation $(parent).on('click', '.child', fn) fits dynamically added elements.
- jQuery 3.x removed the success/error callbacks from $.ajax(); use Promises instead.
- For new projects prefer native DOM APIs or Vue/React; jQuery is mainly for legacy maintenance.
FAQ
What is the actual difference between children() and find()?
It is search depth. children("li") inspects only the direct children of the matched elements — one level, no deeper. find("li") walks all descendants at any depth. For markup div#box > ul > li > a, $("#box").children("li") returns nothing because the li is not a direct child of the box, while $("#box").find("li") finds them. So use children when you mean the immediate tier, such as the second level of a menu, and find when you mean any match within the subtree, such as every link inside a table. Form pseudo-selectors like $(":checkbox") and $(":input") can narrow the result further with filter.
When reading a value, how do I choose between html(), text(), val(), attr() and data()?
Pick by the kind of value you want. html() returns the innerHTML of the first match and is what you use to write a rich fragment — $("#box").html("<p>content</p>") swaps out the old child nodes wholesale. text() returns merged plain text and is the safe choice for writing words because it sidesteps HTML escaping. val() is exclusively for the current value of a form control, so use it for inputs and selects. attr("data-id") reads the HTML attribute, working for custom and native attributes alike, and $("#box").attr("data-id", "123") attaches data for a callback to read. data("key") reads the element's data-key storage; jQuery caches it on first read, so later direct attribute edits do not sync — clear it with .removeData().
My list is generated by AJAX, so the click handler never fires — why?
A handler bound directly to an element cannot work if the element did not exist at binding time. There are two ways out. Delegate to a stable ancestor: $(document).on("click", ".btn", fn), where ".btn" is the second argument; the match happens when the event bubbles up, so elements inserted later fire correctly too. Or wait for the DOM with $(document).ready(fn) (or the shorthand $(fn)) before binding — but that still does nothing for content added after the page is ready. Unbind with $("#btn").off("click"), and call off before re-binding to stop one click firing several times. For form events use $("input").change(fn) and $("form").submit(fn).
How should $.ajax be written in jQuery 3.x so it stops warning about deprecation?
Version 3.x removed the success / error callback style from $.ajax() in favour of Promises. The shorthands still accept callbacks — $.get("/api/data", fn), $.post("/api/data", { key: "value" }, fn) and $.getJSON("/api/data", fn) — but if you want then/catch you must call $.ajax({ url, method, data, success }) in its full form and use the returned jqXHR. For headers, set them once globally with $.ajaxSetup({ headers: { "X-Token": token } }) so every request carries the token without repeating a headers object. As a rule of thumb: reach for the shorthands for plain GETs and JSON reads, and drop to $.ajax only when you need promise chaining, explicit method control, or shared configuration.
Should I use show/hide, fadeIn/slideUp, or animate for showing things?
Decide by whether you want a transition. show(), hide() and toggle() switch visibility instantly, which suits plain expand/collapse logic such as dropdown menus and modals. When an animation is wanted, use fadeIn() / fadeOut() for opacity, or slideDown() / slideUp() for a vertical reveal — the latter fits accordions and detail expanders best because the height change looks natural rather than abrupt. For full control use animate({ left: "200px" }, 500), where the second argument is the duration in milliseconds and the object lists the properties to tween. If what you really need is a state flip, use the class methods: addClass("active"), removeClass("active") and toggleClass("active"), the last being the cheapest on/off switch.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us