jQuery helps you select elements, react to clicks, change the page, and send requests with compact, readable code.
jQuery isn’t the newest kid on the block, yet you’ll still run into it in WordPress themes, older dashboards, internal tools, and plenty of “works fine, don’t touch it” pages. If your job is to maintain, extend, or safely refactor that code, knowing jQuery pays off.
This article shows how to get jQuery on the page, write selectors that don’t bite you later, handle events without spaghetti, update the DOM without weird side effects, and talk to servers in a way that’s easy to debug. You’ll also see where jQuery fits today and where modern JavaScript is the better move.
What jQuery does and where it still fits
jQuery is a JavaScript library that wraps common browser tasks behind a consistent API. It smooths over rough edges, makes DOM selection and updates terse, and offers handy patterns like chaining.
It shines when you’re working inside an existing codebase that already depends on it, when you’re writing small interactive features in a legacy admin panel, or when you need to ship a modest enhancement without rewriting the front end. If you’re starting a large, new UI with state-heavy screens, a modern approach may fit better. Still, for maintenance and small wins, jQuery remains a practical skill.
Getting jQuery on your page
You can load jQuery from a local file you bundle, from a CDN, or from a platform that already ships it. In WordPress, jQuery often comes along for the ride, so loading it twice can cause conflicts. If you control the page and you’re not in a special platform, the simplest setup is a single script tag.
Load jQuery before your script
Place your app script after jQuery so the $ function exists when your code runs.
If you want the official docs for every method you’ll see below, the jQuery API documentation is the canonical reference.
Know what $ means
In jQuery, $ is a function that returns a jQuery object. That object acts like a collection of elements plus a set of methods you can call. You can still access raw DOM nodes when you need them, but most day-to-day work stays in the jQuery layer.
How to Use jQuery
The fastest way to feel comfortable is to master four moves: select, listen, change, and fetch. Once those feel natural, chaining and plugins become straightforward.
Select elements with confidence
Selectors are the heart of jQuery. They look like CSS selectors, which makes them easy to read. The trap is selecting “too much” or selecting on every click when you could cache the result once.
// By id
const $menu = $('#menu');
// By class
const $items = $('.menu-item');
// By attribute
const $email = $('input[type="email"]');
// Inside a container
const $linksInNav = $('#nav').find('a');
Two habits keep selectors sane:
- Scope your search. Select a container, then use
.find()inside it. - Cache what you reuse. Store
const $el = $('#thing')once, then reuse it.
Wait for the DOM before touching it
If your script runs before the HTML exists, selectors return empty sets and nothing happens. jQuery’s ready handler solves that.
$(function () {
// Your code runs after the DOM is ready
$('.menu-item').addClass('is-ready');
});
If you place scripts at the end of , you may not need this. Still, it’s a safe default when you don’t fully control load order.
Read and write text, HTML, and values
jQuery offers clean methods for common content updates. Pick the one that matches what you’re changing.
// Text only (escapes HTML)
$('#status').text('Saved');
// HTML (renders markup)
$('#status').html('Saved');
// Form values
const name = $('#name').val();
$('#name').val('Rikta');
Use .text() when the content can come from users or outside sources. It treats the string as text, not markup, which cuts down the risk of injection bugs.
Add, remove, and toggle classes
Class changes are a clean way to switch UI states without stuffing styles into JavaScript.
$('#panel').addClass('is-open');
$('#panel').removeClass('is-open');
$('#panel').toggleClass('is-open');
Pair this with CSS transitions and your UI changes stay readable.
Change attributes and properties
Attributes like href and data-* are common. Properties like checked and disabled behave like live state on inputs.
// Attributes
$('a.docs').attr('href', '/docs');
const id = $('#row').data('id'); // reads data-id
// Properties
$('#agree').prop('checked', true);
$('#submit').prop('disabled', false);
Use .prop() for boolean-like control states. Use .attr() for string attributes.
Events that don’t turn into a mess
Events are where many jQuery codebases go off the rails. The fix is simple: delegate events when elements can be added later, keep handlers small, and store shared logic in named functions.
Bind events directly
Direct binding is fine when the element exists at load time and won’t be replaced.
$('#saveBtn').on('click', function () {
$('#status').text('Saving...');
});
Use event delegation for dynamic elements
If you inject rows into a table, a direct handler won’t attach to new rows. Delegation attaches once to a stable ancestor, then listens for bubbled events.
$('#cart').on('click', '.remove-item', function () {
$(this).closest('.cart-row').remove();
});
This pattern is a lifesaver in pages that render UI in chunks.
Prevent defaults and stop propagation when needed
Some actions need control. Links navigate, forms submit, and nested click handlers can fire in a chain.
$('a.modal-link').on('click', function (e) {
e.preventDefault();
openModal($(this).attr('href'));
});
$('#inner').on('click', function (e) {
e.stopPropagation();
});
Use these sparingly. If every handler stops propagation, the page becomes hard to reason about.
Table of common jQuery tasks and the methods behind them
The table below acts like a “grab and go” map. It’s not meant to replace the docs. It’s meant to help you recognize patterns fast when you land in an unfamiliar codebase.
| Task | jQuery methods | Notes |
|---|---|---|
| Select by id or class | $('#id'), $('.class') |
Cache repeated selections in a $-prefixed variable. |
| Find inside a container | $parent.find(selector) |
Reduces accidental matches across the page. |
| Read or set text | .text() |
Safer than .html() for user-provided strings. |
| Read or set HTML | .html() |
Use when you own the markup you’re injecting. |
| Toggle UI state | .addClass(), .removeClass(), .toggleClass() |
Pairs well with CSS transitions. |
| Attach handlers | .on(event, handler) |
Prefer delegation when elements can be added later. |
| Delegate events | $root.on(event, selector, handler) |
Attaches once to a stable ancestor and catches bubbled events. |
| Read or set input values | .val() |
Works for text inputs, selects, and textareas. |
| Work with boolean states | .prop() |
Use for checked, disabled, selected. |
| Move around the DOM | .closest(), .parent(), .children() |
.closest() is great for “find the row I’m in.” |
DOM changes that stay readable
jQuery makes it easy to change the page. The trick is to keep your updates predictable. If you sprinkle .html() all over, you can wipe out handlers and state without noticing. Prefer small, targeted updates.
Create elements and insert them
You can build elements with jQuery and append them where they belong.
const $notice = $('Saved.');
$('#messages').append($notice);
// Insert before or after
$notice.insertBefore('#footer');
Remove and empty
.remove() deletes matching elements. .empty() clears children but leaves the container in place.
$('.toast').remove();
$('#results').empty();
Work with lists and tables safely
When you add rows repeatedly, build the row once, then append it. This keeps your loop tight and your markup consistent.
function addRow(name, qty) {
const $row = $(`
`);
$row.find('.name').text(name);
$row.find('.qty').text(qty);
$('#cart tbody').append($row);
}
That mix of template markup plus .text() for data keeps the code readable and reduces injection risks.
AJAX and requests you can debug
jQuery can send HTTP requests with $.ajax(), plus shortcuts like $.get() and $.post(). Modern fetch() is also common, yet you’ll still see jQuery requests in older apps and plugins. If you can read them, you can maintain them.
Use $.get() and $.post() for simple calls
$.get('/api/status', function (data) {
$('#status').text(data.message);
});
$.post('/api/save', { name: 'Ada' }, function (data) {
$('#status').text('Saved: ' + data.id);
});
Use $.ajax() for finer control
When you need headers, timeouts, or explicit data types, $.ajax() gives you knobs to turn.
$.ajax({
url: '/api/items',
method: 'GET',
dataType: 'json',
timeout: 8000
})
.done(function (items) {
renderItems(items);
})
.fail(function (xhr, status) {
$('#status').text('Request failed: ' + status);
});
If you’re unsure which method fits a case, the jQuery AJAX learning page lays out patterns and options in plain language.
Avoid silent failures
Many “AJAX bugs” are just missing error handling. Always attach .fail() or pass an error callback. Also log the response body when you can, since servers often return helpful messages.
.fail(function (xhr) {
console.log('Status:', xhr.status);
console.log('Body:', xhr.responseText);
});
Effects and animation without overdoing it
jQuery ships with simple effects like .hide(), .show(), and .fadeIn(). They’re fine for light UI polish in older pages. For modern motion work, CSS transitions often feel smoother and keep concerns separate.
$('#panel').slideDown(150);
$('#panel').slideUp(150);
$('#toast').fadeIn(120).delay(1500).fadeOut(200);
If your UI relies on these effects, keep durations short. Long animations can make a page feel sluggish.
Table of jQuery vs modern JavaScript equivalents
You don’t need to pick a side forever. Many teams keep jQuery where it already exists and write new features in modern JavaScript. The table below helps you translate between the two styles while you refactor.
| Goal | jQuery | Modern JavaScript |
|---|---|---|
| Select one element | $('#id') |
document.querySelector('#id') |
| Select many elements | $('.item') |
document.querySelectorAll('.item') |
| Add a class | $el.addClass('on') |
el.classList.add('on') |
| Read text | $el.text() |
el.textContent |
| Set HTML | $el.html('x') |
el.innerHTML = 'x' |
| Handle a click | $el.on('click', fn) |
el.addEventListener('click', fn) |
| Send a request | $.ajax(...) |
fetch(url).then(...) |
| Run after DOM load | $(fn) |
document.addEventListener('DOMContentLoaded', fn) |
Chaining, collections, and the “jQuery way”
Chaining is one reason jQuery feels smooth. Many methods return the same jQuery object, so you can apply multiple changes in a single statement. That can read well, as long as you keep it short.
$('#banner')
.addClass('is-visible')
.text('Hello')
.fadeIn(120);
When a chain starts to sprawl, split it. Your future self will thank you.
Iterate over matched elements
jQuery collections can be looped with .each().
$('.tag').each(function () {
const $tag = $(this);
$tag.text($tag.text().trim());
});
Inside .each(), this is a raw DOM node. Wrapping it with $(this) gives you jQuery methods again.
Common gotchas and how to avoid them
Most jQuery pain comes from a few repeat offenders. Fix these patterns and the codebase often feels calmer right away.
Mixing raw DOM nodes and jQuery objects
Raw DOM nodes don’t have jQuery methods. jQuery objects aren’t raw nodes. If you’re unsure which you have, check the variable name. Many teams prefix jQuery objects with $, like $btn.
const el = document.querySelector('#saveBtn'); // DOM node
const $el = $('#saveBtn'); // jQuery object
Binding the same handler multiple times
If you bind in a function that runs repeatedly, clicks can fire twice, then three times, then you’re chasing ghosts. Bind once at startup, or remove old handlers before rebinding.
$('#saveBtn').off('click').on('click', onSave);
Replacing big chunks of HTML and losing handlers
If you call .html() on a container, you wipe and recreate its children. Direct event bindings on those children vanish. Delegation avoids that, since the handler lives on an ancestor that stays put.
Relying on global state
Global variables make bugs travel. Tuck state into a small module-like object, or store state on the DOM via data-* when it makes sense. Keep the surface area small and explicit.
Clean patterns for “real page” features
If you need to add a feature to an older page, aim for a small, tidy structure: one init function, named handlers, cached elements, and clear boundaries.
(function () {
const $form = $('#settingsForm');
const $status = $('#status');
function setStatus(msg) {
$status.text(msg);
}
function onSubmit(e) {
e.preventDefault();
setStatus('Saving...');
$.ajax({
url: $form.attr('action'),
method: 'POST',
data: $form.serialize(),
dataType: 'json'
})
.done(function () {
setStatus('Saved');
})
.fail(function () {
setStatus('Save failed');
});
}
$(function () {
$form.on('submit', onSubmit);
});
})();
This style keeps the global namespace clean, makes it easy to find entry points, and keeps handlers focused.
When to keep jQuery and when to move on
If a site already uses jQuery across many pages, ripping it out for sport can create risk with little payoff. Keeping it for legacy screens can be the practical move. New pages can use modern JavaScript, or a modern UI stack, while older pages stay stable.
If you do refactor, start with small swaps: replace a selector-heavy utility with querySelector, replace a tiny AJAX call with fetch, or remove a plugin that’s causing pain. Each small change reduces coupling without breaking everything at once.
Once you can read and write jQuery comfortably, you gain a valuable maintenance skill: you can land in an older codebase, make changes without fear, and leave the code cleaner than you found it.
References & Sources
- jQuery.“jQuery API Documentation.”Official reference for core jQuery methods, selectors, events, and utilities.
- jQuery Learning Center.“AJAX.”Official learning material for making requests with jQuery, including common patterns and options.
