
ReactJS
Event delegation means attaching a single handler to a parent element and responding to events from multiple children. It's efficient and elegant.
Events "bubble" up from children to parents. This is key to delegation:
function BubblingExample() {
const handleClick = (e) => {
console.log("Clicked element:", e.target.tagName);
};
return (
<div onClick={handleClick}>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</div>
);
}When you click any button, the click event bubbles up to the parent `div`, and the handler fires. The `e.target` tells you which element was actually clicked.
Instead of attaching handlers to each item, delegate to the parent:
function ItemList() {
const [items] = useState([
{ id: 1, label: "Item 1" },
{ id: 2, label: "Item 2" },
{ id: 3, label: "Item 3" },
]);
const handleItemClick = (e) => {
// Check if clicked element is a button
if (e.target.tagName === "BUTTON") {
const id = e.target.dataset.id;
console.log("Clicked item:", id);
}
};
return (
<ul onClick={handleItemClick}>
{items.map((item) => (
<li key={item.id}>
<button data-id={item.id}>{item.label}</button>
</li>
))}
</ul>
);
}Use `data-*` attributes to pass data and check `e.target` to identify which element was clicked.
<details>
<summary>📚 More Examples</summary>
// Handling different actions on different elements
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "Learn React", done: false },
{ id: 2, text: "Build app", done: false },
]);
const handleListClick = (e) => {
const button = e.target.closest("button");
if (!button) return;
const id = parseInt(button.dataset.id);
const action = button.dataset.action;
if (action === "toggle") {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
} else if (action === "delete") {
setTodos(todos.filter((todo) => todo.id !== id));
}
};
return (
<ul onClick={handleListClick}>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}
<button data-id={todo.id} data-action="toggle">
{todo.done ? "Undo" : "Done"}
</button>
<button data-id={todo.id} data-action="delete">
Delete
</button>
</li>
))}
</ul>
);
}</details>
`e.target.closest()` is more reliable than checking `tagName`:
function Form() {
const handleFormClick = (e) => {
// Find the nearest button, even if you clicked inside it
const button = e.target.closest("button");
if (button) {
console.log("Button clicked:", button.textContent);
}
};
return (
<form onClick={handleFormClick}>
<button type="button">
<span>Click me</span>
</button>
<button type="button">Or me</button>
</form>
);
}Store data in `data-*` attributes and retrieve with `dataset`:
function ColorPicker() {
const [selected, setSelected] = useState("red");
const handleColorClick = (e) => {
const button = e.target.closest("button");
if (button) {
const color = button.dataset.color;
setSelected(color);
}
};
const colors = ["red", "blue", "green"];
return (
<div>
<div onClick={handleColorClick}>
{colors.map((color) => (
<button
key={color}
data-color={color}
style={{
background: color,
opacity: selected === color ? 1 : 0.5,
}}
>
{color}
</button>
))}
</div>
<p>Selected: {selected}</p>
</div>
);
}function TaskManager() {
const [tasks, setTasks] = useState([
{ id: 1, text: "Learn React", priority: "high" },
{ id: 2, text: "Build project", priority: "high" },
{ id: 3, text: "Deploy app", priority: "low" },
]);
const handleTaskAction = (e) => {
const button = e.target.closest("button");
if (!button) return;
const taskId = parseInt(button.dataset.id);
const action = button.dataset.action;
if (action === "delete") {
setTasks(tasks.filter((task) => task.id !== taskId));
} else if (action === "increase-priority") {
setTasks(
tasks.map((task) =>
task.id === taskId
? { ...task, priority: "high" }
: task
)
);
}
};
return (
<div onClick={handleTaskAction}>
{tasks.map((task) => (
<div key={task.id} style={{ borderBottom: "1px solid gray" }}>
<p>
{task.text} <strong>[{task.priority}]</strong>
</p>
<button data-id={task.id} data-action="increase-priority">
Increase Priority
</button>
<button data-id={task.id} data-action="delete">
Delete
</button>
</div>
))}
</div>
);
}Ready to practice? Performance & Events | Challenges
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward