jQuery .on() Method

Beginner
⏱️ 13 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Bind handlers

What You’ll Learn

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

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.

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.

📝 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).

2. Events map — .on( events [, selector ] [, data ] )

jQuery
$( "div.test" ).on({
  click: function() { $( this ).toggleClass( "active" ); },
  mouseenter: function() { $( this ).addClass( "inside" ); },
  mouseleave: function() { $( this ).removeClass( "inside" ); }
});

Direct vs delegated binding

jQuery
// Direct — handler on the button itself
$( "#save" ).on( "click", saveHandler );

// Delegated — handler on #list, filter "li"
$( "#list" ).on( "click", "li", selectItem );

// Document-level delegation (replaces .live())
$( document ).on( "click", "p", paragraphHandler );

Legacy migration template

jQuery
// .bind()  →  .on()
$( "#btn" ).bind( "click", fn );
$( "#btn" ).on( "click", fn );

// .delegate()  →  .on()  (note argument order change!)
$( "#list" ).delegate( "li", "click", fn );
$( "#list" ).on( "click", "li", fn );

// .live()  →  .on() on document
$( "p" ).live( "click", fn );
$( document ).on( "click", "p", fn );

Return value

  • Returns the original jQuery object for chaining.
  • The same handler can be bound multiple times (especially useful with different eventData).

⚡ Quick Reference

GoalCode
Direct click handler$("#btn").on("click", fn)
Delegated click on li$("#list").on("click", "li", fn)
Pass data to handler$("p").on("click", { id: 1 }, fn)
Multiple events at once$("div").on({ click: fn1, mouseenter: fn2 })
Namespaced handler$("form").on("submit.myApp", fn)
Custom event$("p").on("myEvent", fn)
Added injQuery 1.7

📋 .on() vs .bind() vs .delegate() vs .live()

Four binding methods from different jQuery eras. Only .on() should be used in modern projects.

.on()
Unified API

Direct + delegated since 1.7 — recommended

.bind()
Direct only

Same element binding — deprecated 3.0

.delegate()
sel, type, fn

Root delegation — deprecated 3.0

.live()
document-level

Always on document — removed 1.9

Examples Gallery

All five examples follow the official jQuery API documentation for .on(). Use the Try-it links to attach handlers and see them fire interactively.

📚 Official API Examples

Five patterns from api.jquery.com/on/.

Example 1 — Display a Paragraph’s Text on Click

The simplest direct binding: attach a click handler to every p element.

jQuery
$( "p" ).on( "click", function() {
  alert( $( this ).text() );
});
Try It Yourself

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.

jQuery
function myHandler( event ) {
  alert( event.data.foo );
}

$( "p" ).on( "click", { foo: "bar" }, myHandler );
Try It Yourself

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( "

Another paragraph! " + (++count) + "

" ); });
Try It Yourself

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.

jQuery
$( "div.test" ).on({
  click: function() {
    $( this ).toggleClass( "active" );
  },
  mouseenter: function() {
    $( this ).addClass( "inside" );
  },
  mouseleave: function() {
    $( this ).removeClass( "inside" );
  }
});
Try It Yourself

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().

jQuery
$( "p" ).on( "myCustomEvent", function( event, myName ) {
  $( this ).text( myName + ", hi there!" );
  $( "span" ).text( "myName = " + myName ).fadeIn( 30 ).fadeOut( 1000 );
});

$( "button" ).click(function() {
  $( "p" ).trigger( "myCustomEvent", [ "John" ] );
});
Try It Yourself

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().

🚀 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.

📝 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.

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 Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All 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.

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.

💡 Best Practices

✅ Do

  • Use delegation on a stable parent for AJAX-loaded content
  • Namespace plugin handlers: .on("click.myPlugin", fn)
  • 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

Key Takeaways

Knowledge Unlocked

Six things to remember about .on()

The modern way to bind jQuery events.

6
Core concepts
🚀 02

Dynamic

Future elements.

Delegate
data 03

eventData

event.data

Config
{ } 04

Object

Multi-event map.

Batch
.ns 05

Namespace

Scoped cleanup.

Plugins
1.7 06

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.

Next: .one() Method

Learn one-shot handlers that auto-remove after the first run.

.one() tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful