Skip to content
TaeyoungKim.dev

JavaScript Event Bubbling and Delegation: Handle Clicks on New List Items

WebWritten 2 min readTaeyoungKim
LinkedInX

If you attached a click listener to every list button but a newly added item does not respond, that new DOM node has no listener. Event delegation uses bubbling—the event's path from a child toward its ancestors—to avoid attaching a listener to every item.

Register one listener on the parent

A click on a button in a newly added li bubbles through the li to the parent ul listener. event.target and event.currentTarget are different; clicks without a matching button are ignored.

html
<ul id="todos">
  <li><button data-action="remove">Remove</button> First task</li>
</ul>
js
const todos = document.querySelector("#todos");

todos.addEventListener("click", (event) => {
  const button = event.target.closest("button[data-action='remove']");
  if (!button || !todos.contains(button)) return;
  button.closest("li")?.remove();
});

The click starts on the button and bubbles through the li to the ul. Because the ul exists from the beginning, its listener can also receive clicks on buttons added later. closest finds the intended button even if the user clicks an icon or span inside it.

Run the following code to create another item before removing the first. The same parent listener handles its button even though no listener was attached to the new button. Clicking text outside a button should leave the item in place.

js
const item = document.createElement("li");
const button = document.createElement("button");
button.dataset.action = "remove";
button.textContent = "Remove";
item.append(button, " Second task");
todos.append(item);

Distinguish target from currentTarget

event.target is the innermost element actually clicked; event.currentTarget is the element whose listener is running. In this example, the target could be an icon, but the current target is always the ul. Confusing them can make the removal logic run even when the user clicks outside a button.

Delegation is not the answer for every event

Direct listeners may be easier to read when each input element manages independent state. Delegation also assumes the actual interactive control is a <button> so keyboard users can activate the same function.

stopPropagation() can prevent the parent action, but it may also cut off events needed by higher-level analytics, dismissal controls, or accessibility features. Design the event flow first, then stop propagation only at the component boundary where it is necessary.

Key takeaways

Event delegation uses bubbling to handle a list with one listener on the parent. It naturally includes new items, but you must distinguish target from currentTarget and use closest to identify the intended control. Build clickable UI with buttons rather than generic div elements so it also works from a keyboard.

Author

TaeyoungKim

Connecting technical foundations with implementation, verification, and production decisions.

#JavaScript#event bubbling#event delegation

Read next