Bubbling, Capturing & Delegation

Understand how events travel through the DOM tree. Learn how to use Event Delegation to write highly performant, memory-efficient listeners.

JavaScript6 min readConcept 44 of 62

The Event Ripple

When you click a <button> that is nested inside a <div>, you aren't just clicking the button. Technically, you are also clicking the <div>, the <body>, and the entire document.

The browser handles this using a process called **Event Bubbling**. When an event fires, it triggers the listener on the innermost target element first, and then "bubbles" upwards through the ancestors, triggering their listeners one by one.

Event Delegation

Bubbling is incredibly useful because it enables a pattern called **Event Delegation**.

Imagine a shopping cart with 100 'Delete' buttons. Attaching 100 individual event listeners consumes massive amounts of browser memory. Instead, you can attach exactly **one** event listener to the parent <ul> container.

When a user clicks a 'Delete' button, the click event bubbles up to the <ul>. Inside the <ul>'s listener, you inspect e.target to figure out which specific button caused the ripple!

Implementing Delegation

Here is how you write a delegated listener:

javascript document.getElementById('cart-list').addEventListener('click', (e) => { if (e.target.classList.contains('delete-btn')) { e.target.parentElement.remove(); } });

Notice how we check e.target before acting. This ensures we only run our logic if the user clicked the button, not if they clicked the empty space inside the <ul>.

Visualizing Delegation

Study the architecture diagram below. It illustrates why placing a single listener on an ancestor node is vastly superior to placing listeners on every child.

The Event Delegation Architecture

// ❌ BAD: 100 individual listeners (Memory Leak)buttons.forEach(btn => {
btn.addEventListener('click', ...);
});
// ✅ GOOD: 1 Delegated Listener on the ParentulElement.addEventListener('click', (e) => {
// Verify they clicked a button, not the empty spaceif (e.target.tagName === 'BUTTON') {
// e.target is the specific button!
// We caught the bubble!
}
});
<ul id="cart">
LISTENER ATTACHED
<li>Item 1</li>
Delete
<li>
Delete
e.target

1. Click Button 2. Event Bubbles Up 3. Parent Catches It

iNotice how the <ul> holds the single event listener. When the nested button is clicked, the event automatically bubbles upward into the parent's listener. We then inspect e.target to perform the action safely!

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1What is Event Bubbling?
  2. 2Why is Event Delegation preferred for dynamic lists (like a to-do list)?
  3. 3How do you prevent an event from bubbling up to parent elements?

Remember this

  • Events 'bubble' upwards from the target element all the way to the document root.
  • Use e.stopPropagation() to stop the event from bubbling further.
  • Event Delegation involves placing a single listener on a parent element to handle events from its children.
  • Delegation is highly memory-efficient and automatically handles newly injected DOM elements.
  • Inside a delegated listener, check e.target to verify exactly what was clicked before acting.

Done with this concept?

Mark it complete to track your progress. No login needed.