Event bubbling is a core concept in JavaScript’s event model. It describes how events propagate through the DOM hierarchy after they are triggered on an element.
In simple terms: when an event happens on a child element, it automatically travels upward to its parent elements, one by one, until it reaches the document root.
This behavior is the default for most DOM events.
The DOM Event Flow (Important Context)
Before understanding bubbling, you must understand how events flow in the DOM. JavaScript events move in three phases:
- Capturing phase – event travels from the
documentdown to the target element - Target phase – event reaches the actual element that triggered it
- Bubbling phase – event bubbles up from the target back to the
document
Event bubbling refers only to the third phase.
Basic Example of Event Bubbling
HTML structure:
<div id="parent"><br> <button id="child">Click me</button><br></div><br>JavaScript:
document.getElementById('parent').addEventListener('click', () => {<br> console.log('Parent clicked');<br>});<br><br>document.getElementById('child').addEventListener('click', () => {<br> console.log('Child clicked');<br>});<br>What happens when the button is clicked?
Output:
Child clicked
Parent clicked
Explanation:
- The click occurs on
#child - The event is handled by the child first
- Then it bubbles up to
#parent
Why Event Bubbling Exists
Event bubbling is not a bug. It is a design feature that enables:
- Efficient event handling
- Cleaner code
- Dynamic UI behavior
Without bubbling, many modern JavaScript patterns would be inefficient or impossible.
Event Delegation (The Real Power of Bubbling)
Event delegation is the most practical use of event bubbling.
Instead of attaching event listeners to multiple child elements, you attach one listener to a common parent.
Example: List Items
<ul id="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
document.getElementById('list').addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log(event.target.textContent);
}
});
Why this works
- Click happens on
<li> - Event bubbles up to
<ul> - Parent listener handles it using
event.target
Benefits
- Fewer event listeners
- Better performance
- Works with dynamically added elements
event.target vs event.currentTarget
This distinction is critical.
- event.target → element that actually triggered the event
- event.currentTarget → element where the event listener is attached
parent.addEventListener('click', function (event) {
console.log(event.target); // actual clicked element
console.log(event.currentTarget); // parent element
});
Misunderstanding this is a common source of bugs.
Stopping Event Bubbling
Sometimes bubbling is not desired. JavaScript provides control.
stopPropagation()
child.addEventListener('click', (event) => {
event.stopPropagation();
console.log('Child only');
});
Result:
- Event stops at the child
- Parent handlers will not execute
stopImmediatePropagation()
Stops:
- Bubbling
- Capturing
- Other listeners on the same element
Use with caution.
Events That Do NOT Bubble
Not all events bubble by default.
Common non-bubbling events:
focusblurmouseentermouseleave
Bubbling alternatives exist:
focusininstead offocusfocusoutinstead ofblur
Bubbling vs Capturing (Quick Comparison)
| Feature | Capturing | Bubbling |
|---|---|---|
| Direction | Top → Bottom | Bottom → Top |
| Default | No | Yes |
| Common usage | Rare | Very common |
| Event Delegation | No | Yes |
Real-World Use Cases
- Dropdown menus
- Modal close handling
- Table row clicks
- SPA navigation handling
- Dynamic form validation
Most UI frameworks internally rely on event bubbling.
Common Mistakes
- Adding listeners to every child unnecessarily
- Forgetting
event.targetchecks in delegation - Using
stopPropagation()globally - Confusing bubbling with capturing
Key Takeaways
- Event bubbling is default DOM behavior
- Events move upward through parent elements
- Enables event delegation
- Improves performance and scalability
- Essential for modern JavaScript development
Understanding event bubbling is mandatory for writing clean, efficient, and scalable frontend code.

