Event Handling
|
This section documents jQuery 3.x (the current major line — no specific patch version is pinned). This content was generated with the assistance of AI and should be verified against the official jQuery API reference before being relied on in production, since API details and deprecations continue to change between releases. jQuery is legacy-leaning: modern browsers implement native equivalents for almost everything it does
( This section’s bibliography lists the reference material consulted while preparing these pages. |
.on() is the single method for attaching event handlers in modern jQuery. It registers a normalised,
cross-browser event object and supports delegation. The older .bind(), .live(), and .delegate() are all
removed or deprecated — everything they did, .on() does.
Binding handlers
$('#btn').on('click', handler); // direct binding
$('#btn').on('click', { id: 42 }, handler); // pass data -> event.data.id
$('#btn').on('mouseenter mouseleave', handler); // several event types at once
$('#btn').one('click', handler); // auto-removes itself after the first call
$('#btn').off('click', handler); // remove one specific handler
$('#btn').off('click'); // remove all click handlers
$('#btn').off(); // remove every handler on the element
Shorthand methods exist for the common events — .click(), .dblclick(), .hover(inFn, outFn), .focus(),
.blur(), .change(), .submit(), .keydown(), .keyup(), .keypress(), and the mouse family
(.mousedown(), .mouseup(), .mousemove(), .mouseenter(), .mouseleave()). Since jQuery 3.3 the
no-argument signatures (.click() to trigger a click) are deprecated; call .trigger('click') instead.
The one-argument forms (.click(handler)) still work but .on('click', handler) is preferred for
consistency and because only .on() supports delegation.
The jQuery event object
The handler receives one argument: a jQuery-normalised event. this and event.currentTarget are the element
the handler is bound to.
$('#form').on('submit', function (event) {
event.type; // "submit"
event.target; // the deepest element the event originated on
event.currentTarget; // === this: the element this handler is attached to
event.which; // normalised key/button code (legacy)
event.key; // "Enter", "a", ... (modern, from the native event)
event.pageX; // pointer X relative to the document
event.data; // the data object passed as .on('submit', data, fn)
event.preventDefault(); // cancel the default action (no form submit)
event.stopPropagation(); // stop the event bubbling to ancestors
event.stopImmediatePropagation(); // also skip this element's remaining handlers
return false; // shorthand for BOTH preventDefault + stopPropagation
});
In a jQuery handler return false is preventDefault() and stopPropagation(). In a native
listener return false does nothing. This difference trips people up when porting code.
|
Event delegation
Bind one handler to a stable ancestor and pass a selector as the second argument. jQuery checks, at event
time, whether event.target (or an ancestor of it, up to currentTarget) matches that selector:
// direct: only binds to the <li> that exist RIGHT NOW
$('#list li').on('click', handler);
// delegated: one handler on #list; works for <li> added later too
$('#list').on('click', 'li', function (event) {
$(this).toggleClass('done'); // `this` is the matched <li>, not #list
});
Delegation matters for two reasons: dynamically added elements get the behaviour with no re-binding, and one listener uses less memory than hundreds. It is the standard pattern for lists, tables, and any repeated markup.
Triggering and custom events
$('#btn').trigger('click'); // fire click: handlers run AND default action
$('#btn').trigger('click', [arg1, arg2]); // pass extra args to the handlers
$('#btn').triggerHandler('click'); // run handlers only: no default, no bubbling
$(document).on('cart:add', (e, item) => updateBadge(item)); // custom event
$(document).trigger('cart:add', { sku: 'A1' }); // fire it with data
$('#btn').on('click.plugin', handler); // namespaced
$('#btn').off('.plugin'); // remove every handler in the .plugin namespace
Namespaces let a plugin (or a component) remove exactly its own handlers without disturbing others.
Window and document events
$(window).on('resize', handler);
$(window).on('scroll', handler); // consider throttling -- fires rapidly
$(window).on('load', handler); // after all images/resources; rarely needed
Modern equivalent
el.addEventListener(type, handler, options) and removeEventListener. There is no built-in delegation — attach to a container and test inside: container.addEventListener('click', e ⇒ { const li =
e.target.closest('li'); if (li) … }). Dispatch custom events with new CustomEvent('cart:add', { detail })
and el.dispatchEvent(…). For the full capture/target/bubble model see
Events.