The .on() method attaches event handlers to elements. Since jQuery 1.7 it is the single recommended way to bind events — direct handlers, delegated handlers for dynamic DOM, eventData, namespaces, and custom events. This tutorial covers all official signatures, five worked examples from the jQuery API, and migration from legacy methods.
01
Syntax
.on(type, sel, fn)
02
Direct
Bind on element
03
Delegate
Future children
04
eventData
Pass to handler
05
Object map
Multiple events
06
Since 1.7
Modern API
Fundamentals
Introduction
Every interactive web page reacts to user input — clicks, keystrokes, form submissions. jQuery’s .on() method is how you connect those browser events to your JavaScript functions. Introduced in version 1.7, it replaced a patchwork of older methods (.bind(), .delegate(), .live()) with one flexible API.
Whether you need a simple click handler on a button, delegation on a list that grows dynamically, or a custom event your components trigger among themselves, .on() handles it. Pair it with .off() to remove handlers when widgets are destroyed or routes change.
Concept
Understanding .on()
When you call $("#btn").on("click", handler), jQuery stores your function in an internal event registry on that element. The next time a click bubbles through the element, jQuery calls your handler with a normalized event object and sets this to the element where the handler is being delivered.
Add a selector argument and the handler becomes delegated: jQuery listens on the parent but only runs the handler when the event originated from a descendant matching the selector. That is how one handler on tbody can serve 1,000 table rows — and rows added later.
💡
Beginner Tip
Elements must exist when you call .on() on them directly. For content loaded later, either bind inside $(document).ready() after HTML is present, or attach a delegated handler on a stable parent (or document) that is always in the page.
Foundation
📝 Syntax
Two main signatures from the official jQuery API (both since 1.7):
1. Handler function — .on( events [, selector ] [, data ], handler )
jQuery
.on( events [, selector ] [, data ], handler )
events — one or more space-separated types with optional namespaces (e.g. "click", "keydown.myPlugin").
selector — descendant filter for delegation; omit for direct binding.
data — plain object copied to event.data when the handler runs.
handler — function to run, or false as shorthand for return false (preventDefault + stopPropagation).
Click any paragraph → alert shows its text
this refers to the clicked p element
$(this).text() reads the paragraph content
How It Works
With no selector argument, the handler is directly bound. jQuery sets this to the element that received the event. Wrap it with $( this ) to use jQuery methods.
Example 2 — Pass eventData to the Handler
Supply a data object; jQuery exposes it as event.data inside the handler.
Click paragraph → alert shows "bar"
Same handler bound twice with different data → different alerts
event.data is set per binding, not per element
How It Works
The third argument (when no selector is used) is copied to event.data each time the event fires. Bind the same named function with different data objects to reuse one handler for multiple configurations.
Example 3 — Delegated Click Adds New Paragraphs
Official dynamic-DOM demo: one handler on body handles clicks on any p, including paragraphs added later.
jQuery
var count = 0;
$( "body" ).on( "click", "p", function() {
$( this ).after( "
Click "Click me!" → new paragraph appended
Click the new paragraph → another one appears
Handler bound once on body — no rebinding needed
How It Works
Delegation listens on body but filters to p descendants. When you append new paragraphs, they automatically participate because the handler was never attached to individual p elements. This replaces the old .live() pattern with better performance control.
Example 4 — Bind Multiple Events with a Plain Object
Attach click, mouseenter, and mouseleave handlers in one call.
Hover div.test → adds "inside" class
Mouse leave → removes "inside"
Click → toggles "active" class
How It Works
Object keys are event type strings (with optional namespaces). Values are handler functions or false. You can optionally pass a delegation selector as the second argument to the object form.
Example 5 — Attach and Trigger a Custom Event
Listen for a non-browser event name and fire it with .trigger().
Click button → trigger("myCustomEvent", ["John"])
p text becomes "John, hi there!"
Extra trigger args arrive after the event object
How It Works
Custom events decouple components: the button does not need to know how the paragraph reacts. Extra parameters after event come from the array passed to .trigger().
Applications
🚀 Common Use Cases
Button clicks — $("#save").on("click", saveForm) for direct UI actions.
Dynamic lists — $("#cart").on("click", ".remove", removeItem) for AJAX-loaded rows.
Form validation — $("form").on("submit.myValidator", validate) with namespace for clean teardown.
Plugin initialization — bind under .myPlugin namespace; destroy with .off(".myPlugin").
Component messaging — custom events like widget:refresh between loosely coupled modules.
Performance — one delegated handler on tbody instead of 1,000 direct handlers on tr.
🧠 How .on() Delivers Events
1
Register handler
jQuery stores your function, selector (if any), namespace, and eventData on the matched element’s internal handler list.
Bind
2
Event bubbles
The browser fires an event; it travels from the target up through ancestors (for bubbling events).
Bubble
3
Match & invoke
At each bound element, jQuery checks type, namespace, and delegation selector, then calls matching handlers with a normalized event object.
Run
4
⚡
this is set
Inside the handler, this is the element where the handler is being delivered — the bound element for direct handlers, or the matching descendant for delegated ones.
Important
📝 Notes
.on() was added in jQuery 1.7 and provides all functionality previously split across .bind(), .delegate(), and .live().
Delegated handlers do not work for SVG elements in jQuery.
Events like load, scroll, and error on some elements do not bubble — delegation is not supported for them; bind directly.
Passing false as the handler is shorthand for a function that calls event.preventDefault() and event.stopPropagation().
Handler order: handlers on the same element run in the order they were bound. Use event.stopImmediatePropagation() to block subsequent handlers on that element.
For one-time handlers, consider .one() instead of manually calling .off() inside the handler.
Attach delegated events as close to the target as possible — avoid $(document.body).on(...) for large apps when a closer container works.
Compatibility
Browser Support
.on() is a jQuery method available since jQuery 1.7 in all jQuery 1.x, 2.x, and 3.x releases. It works in every browser your jQuery version supports. Native equivalent: element.addEventListener(type, fn) — but without jQuery's delegation, namespace, eventData, or multi-handler management.
✓ jQuery 1.7+
jQuery .on()
Supported in jQuery 1.7+ across all modern browsers and IE with supported jQuery builds. The current recommended way to attach event handlers in jQuery. Safe for all new projects.
100%Modern jQuery API
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.on()Universal
Bottom line: Use .on() for every new jQuery project. Pair it with .off() for teardown. Prefer delegation on stable parents for dynamic content instead of rebinding after each DOM update.
Wrap Up
Conclusion
jQuery .on() is the foundation of modern event handling in jQuery. One method covers direct binding, delegation, data passing, multiple events, namespaces, and custom events — replacing three legacy APIs with a consistent argument pattern.
Start with direct handlers for static UI, graduate to delegation for dynamic lists, and namespace your plugin bindings from day one. When you need to remove handlers, the matching .off() tutorial completes the pair.
Attach delegated handlers close to targets, not always on document
Store handler references when you will need .off(type, sel, fn)
Use plain objects for eventData, not strings mistaken for selectors
❌ Don’t
Re-bind the same event without .off() first (duplicate handlers)
Use .live() or .bind() in new jQuery 3 code
Delegate non-bubbling events like scroll on inner elements
Attach thousands of direct handlers when one delegated handler suffices
Forget that elements must exist before direct .on() binding
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about .on()
The modern way to bind jQuery events.
6
Core concepts
📝01
Unified
Direct + delegate.
API
🚀02
Dynamic
Future elements.
Delegate
data03
eventData
event.data
Config
{ }04
Object
Multi-event map.
Batch
.ns05
Namespace
Scoped cleanup.
Plugins
1.706
Modern
Use today.
Status
❓ Frequently Asked Questions
.on() attaches event handlers to the selected elements. It is the modern binding API introduced in jQuery 1.7, replacing .bind(), .delegate(), and .live(). You can bind direct handlers, delegated handlers for dynamic content, pass eventData, use namespaces, and attach multiple events at once.
Direct: $('button').on('click', fn) runs when the button itself is clicked. Delegated: $('#list').on('click', 'li', fn) listens on #list but runs when any matching li is clicked — including li elements added later via AJAX or .append().
.on() unifies both patterns in one API. .bind() only attached direct handlers; .delegate() only attached delegated handlers with selector-first argument order. .on(event, selector, handler) replaces both. Use .off() as the unified unbind counterpart.
Append a dot suffix like .on('click.myPlugin', fn). Namespaces let you remove or trigger only your handlers with .off('.myPlugin') without affecting other click handlers. Namespaces are not hierarchical — one matching name is enough.
Yes. Pass a data object as the third argument: .on('click', { foo: 'bar' }, handler). jQuery copies it to event.data inside the handler. If you also use a selector, pass null explicitly for selector when data is a string to avoid confusion.
Yes. .on('myCustomEvent', fn) listens for events you trigger with .trigger('myCustomEvent') or .trigger('myCustomEvent', [extraData]). Custom events are useful for decoupling components without DOM-native event types.
Did you know?
Attaching 1,000 direct click handlers on table rows forces jQuery to register 1,000 separate entries. A single delegated handler on tbody with selector "tr" handles every row — current and future — with one registration. That performance difference is a major reason jQuery unified delegation into .on() instead of keeping separate APIs.