event.data holds the optional object passed to .on() when a handler is bound. This tutorial covers the official for-loop demo, fixing closure bugs, delegation with eventData, multiple properties, and how event.data differs from .data().
01
Property
event.data
02
eventData
.on(…, { }, fn)
03
Official
Loop index fix
04
Delegate
Action payloads
05
vs .data()
Not the same
06
Since 1.1
Object return
Fundamentals
Introduction
Handlers often need extra context — which row was clicked, what ID to delete, or which menu action to run. jQuery lets you attach a plain object when binding: .on("click", { id: 42 }, handler). Inside the callback, read it as event.data.id.
The official jQuery API documents event.data since version 1.1. Its most famous use is fixing the classic loop closure bug: without eventData, every button in a for loop may report the same final index. Passing { value: i } preserves each iteration’s value on the event object.
Concept
Understanding event.data
event.data is a snapshot of the object you supplied to .on() at bind time:
Direct bind — $("#btn").on("click", { action: "save" }, fn) → event.data.action is "save".
Delegation — $("#list").on("click", "li", { mode: "edit" }, fn) → same event.data for every matching child click.
Loop fix — .on("click", { value: i }, fn) stores each i separately per handler.
Not element storage — unlike $("#el").data(), it travels with the handler binding, not the DOM node.
💡
Beginner Tip
If every button in a loop logs the same number, pass { value: i } to .on() and read event.data.value — that is exactly what the official jQuery demo teaches.
Foundation
📝 Syntax
Pass eventData as the argument before the handler in .on() (since 1.7):
Object — any plain object jQuery can copy onto the event; strings, numbers, nested objects, and booleans are fine.
Return value
Not a method — a read-only property on the event object for the current handler invocation.
Reflects the eventData object passed when this specific handler was bound.
Official jQuery API example
jQuery
var logDiv = $( "#log" );
for ( var i = 0; i < 5; i++ ) {
$( "button" ).eq( i ).on( "click", { value: i }, function ( event ) {
var msgs = [
"button = " + $( this ).index(),
"event.data.value = " + event.data.value,
"i = " + i
];
logDiv.append( msgs.join( ", " ) + " " );
});
}
Cheat Sheet
⚡ Quick Reference
Goal
Code
Pass data on bind
$("#x").on("click", { id: 1 }, fn)
Read in handler
event.data.id
Delegation + data
$("#p").on("click", "li", { a: "x" }, fn)
Fix loop index
.on("click", { value: i }, fn)
Not the same as
$("#el").data("key") — element storage
Compare
📋 event.data vs closures, .data(), and attributes
Four ways to attach context — pick the right tool.
event.data
.on("click", { id: 1 }, fn)
Bind-time payload
IIFE closure
(function(v){ ... })(i)
Capture loop var
.data()
$("#el").data("id", 1)
On DOM element
data-* attr
data-id="1"
HTML markup
Hands-On
Examples Gallery
Example 1 follows the official jQuery event.data demo. Examples 2–5 cover simple payloads, delegation actions, multiple properties, and comparing closure i with event.data.value.
📚 Official jQuery Demo
Five buttons in a loop — event.data.value preserves each index.
Example 1 — Official Demo: loop with { value: i }
Official jQuery demo — each button logs its index via event.data.value while closure i shows the loop pitfall.
jQuery
var logDiv = $( "#log" );
for ( var i = 0; i < 5; i++ ) {
$( "button" ).eq( i ).on( "click", { value: i }, function ( event ) {
var msgs = [
"button = " + $( this ).index(),
"event.data.value = " + event.data.value,
"i = " + i
];
logDiv.append( msgs.join( ", " ) + " " );
});
}
Click button 0 → event.data.value = 0, i = 5 (closure)
Click button 3 → event.data.value = 3, i = 5 (closure)
event.data.value is correct for each button; bare i is wrong after loop
How It Works
jQuery stores a copy of { value: i } per binding. When the handler runs, event.data.value reflects the i from that iteration — not the shared loop variable after the loop finishes.
Example 2 — Simple Payload: { id, label }
Pass a small object when binding — read fields inside the handler without global variables.
Click Remove on any row → row is deleted
event.data.action is "delete" for every delegated click
How It Works
Delegation syntax is .on(event, selector, eventData, handler). The data object is shared by all delegated matches — use $(this) for row-specific DOM work.
Example 4 — Multiple Fields: API endpoint + method
Pass several properties — endpoint, method, and confirm flag — in one eventData object.
Click Sync → confirm dialog (if confirm: true)
AJAX uses url and method from event.data
How It Works
event.data can hold any serializable fields your handler needs. Keep objects plain — jQuery copies them at bind time.
Example 5 — Side-by-Side: wrong closure vs event.data
Bind one button without eventData and one with — compare bare i against event.data.value.
jQuery
for ( var i = 0; i < 3; i++ ) {
$( "#bad-" + i ).on( "click", function () {
console.log( "bad i =", i );
});
$( "#good-" + i ).on( "click", { value: i }, function ( event ) {
console.log( "good value =", event.data.value );
});
}
Plugin config — pass defaults merged with per-element options at bind time.
Testing — bind with predictable payloads; trigger with extra args when needed.
Avoid globals — keep IDs and labels on event.data instead of window state.
🧠 How jQuery Sets event.data
1
Bind with .on()
You pass eventData as the object argument before the handler function.
Bind
2
jQuery stores a copy
Each handler keeps its own snapshot — loop indices and configs do not collide.
Store
3
Event fires
User click or .trigger() invokes the handler with a normalized event object.
Fire
4
✓
Read event.data
Handler reads event.data.field — the payload from bind time for this handler.
Important
📝 Notes
Available since jQuery 1.1 — returns an Object.
Only present when you pass eventData to .on() (or compatible bind APIs).
Not the same as $("#el").data() — that stores data on elements.
Changing event.data in the handler does not update the stored bind payload for future events.
Delegation form: .on(type, selector, data, handler) — data sits before the function.
Modern alternative in loops: let block scope or IIFE — eventData remains the jQuery-native fix.
Compatibility
Browser Support
event.data is part of jQuery’s normalized event object since jQuery 1.1+. It works consistently anywhere jQuery event binding runs — independent of browser, because jQuery attaches the payload when the handler is registered.
✓ jQuery 1.1+ · all browsers
jQuery event.data
Bind-time payload on the event object — fix loop closures cleanly.
100%jQuery only
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
event.dataObject
Bottom line: Pass { value: i } in loops — read event.data.value in handlers.
Wrap Up
Conclusion
event.data carries the optional object you pass to .on() when binding a handler. The official demo shows why it matters in loops: event.data.value keeps each button’s index while a bare closure variable does not.
Use eventData for toolbar actions, delegation, and any handler that needs config without globals. Remember it is bind-time data — not .data() on DOM nodes.
Pass { value: i } in loops — official jQuery pattern
Use plain objects with clear property names
Put delegation data before the handler: .on("click", "li", data, fn)
Guard with if (event.data && event.data.id) when optional
Prefer data-* attributes when values live in HTML markup
❌ Don’t
Confuse event.data with $("#el").data()
Mutate event.data expecting bind storage to update
Share one mutable object across bindings unless intentional
Assume event.data exists without passing eventData
Rely on closure loop variables without let or eventData
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about event.data
Bind-time payload on the event object.
5
Core concepts
data01
event.data
Bind payload
API
.on02
eventData
3rd arg
Syntax
for03
Loop fix
{ value: i }
Demo
li04
Delegate
Shared action
Pattern
.data()05
Not same
DOM storage
Compare
❓ Frequently Asked Questions
event.data is the optional object you pass as the third argument to .on() — .on('click', { value: 1 }, handler). jQuery attaches it to the event object so your handler can read custom values via event.data. Available since jQuery 1.1.
Use .on('click', { key: value }, function(event) { ... }). Inside the handler, read event.data.key. For delegation, use .on('click', 'selector', { key: value }, handler).
Without event.data, all handlers in a loop often share the same closure variable — every click reports the final loop index. Passing { value: i } to .on() captures each iteration value separately on event.data.value.
No. event.data is the object passed when binding a handler with .on(). jQuery .data() stores key-value pairs on DOM elements. They solve different problems — handler context vs element storage.
event.data may be undefined or an empty object depending on jQuery version and binding path. Always pass an object when you rely on custom fields, or guard with if (event.data && event.data.id).
Yes. .trigger('click', [{ id: 42 }]) can supply extra arguments that become available on the event object for triggered handlers — useful for testing. Direct user clicks use the data object from .on() binding.
Did you know?
Before let block scope was widely available, event.data was the idiomatic jQuery way to fix loop index bugs. The official demo still logs both event.data.value (correct) and bare i (wrong after the loop) to teach the difference side by side.