Skip to content

JavaScript Tutorial Events

JavaScript Event Delegation

Lesson 119 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

Imagine a list with 100 items, each with a delete button. You could attach 100 listeners. Or you could attach one to the list, and let bubbling bring the clicks to it. That is event delegation.

index.html
HTML
<ul id="tasks">
  <li>Wash up <button data-action="delete">Delete</button></li>
  <li>Study <button data-action="delete">Delete</button></li>
</ul>
<button id="add">Add task</button>
<script>
  const tasks = document.querySelector("#tasks");

  tasks.addEventListener("click", event => {
    const button = event.target.closest("[data-action='delete']");
    if (!button) return;                    // the click was elsewhere
    button.closest("li").remove();
  });

  document.querySelector("#add").addEventListener("click", () => {
    const li = document.createElement("li");
    li.innerHTML = 'New task <button data-action="delete">Delete</button>';
    tasks.append(li);
  });
</script>

Add a task and delete it: it works even though the new button never had its own listener.

How it works

  1. The listener sits on the parent (#tasks).
  2. A click on a child bubbles up to it.
  3. In the handler, event.target tells you which child was clicked.
  4. closest() finds the element you care about, even if the user clicked something inside it (an icon inside the button, for example).
  5. If it is not what you want, return early.

Why use it

  • Fewer listeners. One instead of hundreds, which uses less memory.
  • Works for elements added later, which is perfect for lists built from data.
  • Less cleanup. Removing an element does not leave a listener behind.

Use closest, not target

event.target is the innermost clicked element, which might be an <svg> or <span> inside your button. target.closest("button") handles that.

script.js
JS
const button = event.target.closest("button");
if (!button || !list.contains(button)) return;

The contains check makes sure the match is inside your container.

Telling items apart

Use data- attributes to carry information, see Data Attributes.

index.html
HTML
<div id="toolbar">
  <button data-tool="bold">B</button>
  <button data-tool="italic">I</button>
</div>
<p id="out"></p>
<script>
  document.querySelector("#toolbar").addEventListener("click", event => {
    const tool = event.target.closest("[data-tool]")?.dataset.tool;
    if (tool) document.querySelector("#out").textContent = "Tool: " + tool;
  });
</script>

When not to use it

For events that do not bubble (focus, blur, mouseenter), use the bubbling alternatives, or attach listeners directly. And for a single, one-off element, a normal listener is simpler.

lightbulb
Where it matters
It is one of the best habits for performance and for dynamic lists. You will use it in the To-Do, Tabs and Accordion projects.