One Handler for All

Event bubbling unlocks one of the most powerful and efficient patterns in front-end development: Event Delegation.

The Problem

Imagine a menu with 100 items. Attaching a separate click listener to each item creates 100 event handlers — a waste of memory. What if items are added dynamically? You'd have to add a new listener every time.

The Solution: Delegation

Instead of attaching handlers to each child, you attach one handler to their common ancestor. Then, inside the handler, you check event.target to see exactly which child was clicked.

const menu = document.querySelector('.menu');

menu.addEventListener('click', function(event) {
  // Find the closest <li> ancestor of what was clicked
  const item = event.target.closest('li');
  
  if (!item) return; // Clicked outside any list item? Do nothing.
  
  console.log('You clicked: ' + item.dataset.action);
});

Why use closest()?

If a list item has an icon inside it: <li><img>Save</li>, clicking the icon makes event.target the <img>, not the <li>. closest('li') safely walks up the tree until it finds the right element.

Tip

Event delegation saves memory, simplifies code, and automatically works for dynamically added elements — no new listeners needed!