JS Event Bubbling and Capturing
In this page:
Event Bubbling
In bubbling, an event starts at the target and moves upward through its ancestors. This is the default event flow in the DOM and is why a click on a button nested deep inside several containers can also trigger listeners on those outer containers.
Example: Event Bubbling
<div id="outer">
<button id="inner">Click</button>
</div>
<script>
document.getElementById("outer").addEventListener("click", () => console.log("Outer (bubbled)"));
document.getElementById("inner").addEventListener("click", () => console.log("Inner (target)"));
</script>
Event Capturing
In capturing, the event travels from the outer ancestor toward the target before bubbling back. Capturing listeners are less commonly used but are registered by passing true (or {capture: true}) as the third argument to addEventListener, running before the target's own listeners fire.
Example: Event Capturing
<div id="outer">
<button id="inner">Click</button>
</div>
<script>
document.getElementById("outer").addEventListener("click", () => console.log("Outer (capture)"), true);
document.getElementById("inner").addEventListener("click", () => console.log("Inner (target)"));
</script>
Stopping Propagation
stopPropagation prevents an event from continuing to other ancestors. Calling it inside a handler stops the event from reaching any ancestor listeners, which is useful when a nested element needs to fully own a particular interaction.
Example: Stopping Propagation
<div id="outer">
<button id="inner">Click</button>
</div>
<script>
document.getElementById("outer").addEventListener("click", () => console.log("Never runs"));
document.getElementById("inner").addEventListener("click", (e) => {
e.stopPropagation();
console.log("Inner only");
});
</script>
stopImmediatePropagation
stopImmediatePropagation stops the current event and prevents other listeners on the same target from running. This is a more targeted stop than stopPropagation — it also blocks any other listeners registered on that same exact element for that same event.
Example: stopImmediatePropagation
<button id="btn">Click</button>
<script>
const btn = document.getElementById("btn");
btn.addEventListener("click", (e) => {
e.stopImmediatePropagation();
console.log("First listener");
});
btn.addEventListener("click", () => console.log("Never runs"));
</script>
Bubbling and Capturing Together
Knowing both phases helps you control the order in which event listeners run. Together, capturing and bubbling define the full three-phase journey (capture down, target, bubble up) that every DOM event travels through.
Example: Bubbling and Capturing Together
<div id="outer">
<button id="inner">Click</button>
</div>
<script>
document.getElementById("outer").addEventListener("click", () => console.log("2: capture"), true);
document.getElementById("inner").addEventListener("click", () => console.log("1: target"));
document.getElementById("outer").addEventListener("click", () => console.log("3: bubble"));
</script>
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: