Introduction
Hey there, fellow developers!
If you've ever wondered why clicking on a nested element sometimes triggers multiple event handlers in a specific order — or why adding true as the third parameter to addEventListener() changes everything — you're in the right place.
Today, we're diving deep into event phases in the DOM. We'll explore the three phases of events, how addEventListener() controls them with its mysterious third parameter, and exactly what happens under the hood when you click an element.
Grab your favorite chai, and let's make this fun and crystal clear!
The Three Parameters of addEventListener()
The addEventListener() method accepts up to three arguments:
element.addEventListener(event, callback, options);
-
event — The event name (e.g.,
"click","mouseover") - callback — The function to run when the event fires
- options — This is where the magic happens! It can be a boolean or an object that specifies characteristics about the event listener.
When you pass a boolean as the third argument:
-
false→ Bubbling phase (this is the default) -
true→ Capturing phase
This third parameter decides when your event handler should run during event propagation.
Event Bubbling vs Event Capturing
Imagine you click on a child element inside a parent. Does the event start at the child and go up? Or start from the top and come down?
-
Bubbling (default,
false): The event starts at the target element and "bubbles up" to its ancestors (bottom → top). -
Capturing (
true): The event starts from the window and "captures down" to the target element (top → bottom).
Most developers only know bubbling because it's the default. But understanding both gives you superpower for complex UIs.
The Three Event Phases
Every DOM event goes through three distinct phases:
-
Capturing Phase (top → bottom) — only runs if listeners were added with
true - Target Phase — the event has reached the actual element that was clicked
- Bubbling Phase (bottom → top) — default behavior
Here's a beautiful diagram that visualizes exactly how these phases flow:
As you can see:
-
Left side shows bottom-up bubbling (default,
false) -
Right side shows top-down capturing (
true) - The flow always starts from
window→html→body→parent→child
Now, let's see this in action with real code!
Live Demo: Understanding All Combinations
Here's our simple HTML structure:
<body>
<div id="parent">
<div id="child">Hello I'm Child</div>
</div>
</body>
We'll add click listeners to both parent and child using different combinations of the third parameter.
Case 1: Both Listeners in Capturing Phase (true)
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.addEventListener("click", () => {
console.log("Parent Clicked (Capturing)");
}, true);
child.addEventListener("click", () => {
console.log("Child Clicked (Capturing)");
}, true);
Output when clicking the child:
Parent Clicked (Capturing)
Child Clicked (Capturing)
Why? Capturing always flow from top to bottom. Parent is higher in the DOM tree, so it fires first.
Case 2: Both in Bubbling Phase (false or omitted)
parent.addEventListener("click", () => {
console.log("Parent Clicked (Bubbling)");
}, false); // or just omit the third parameter
child.addEventListener("click", () => {
console.log("Child Clicked (Bubbling)");
});
Output:
Child Clicked (Bubbling)
Parent Clicked (Bubbling)
Classic bubbling behavior — starts at the target (child) and goes up.
Case 3: Parent Capturing (true), Child Bubbling (false)
parent.addEventListener("click", () => console.log("Parent (Capturing)"), true);
child.addEventListener("click", () => console.log("Child (Bubbling)"));
Output:
Parent (Capturing)
Child (Bubbling)
Why?
Capturing phase runs top-down: the parent’s true listener fires first.
Then the target phase reaches the child, so the child’s listener (registered with false) executes.
Result: Parent first, then Child.
Case 4: Parent Bubbling (false), Child Capturing (true)
parent.addEventListener("click", () => console.log("Parent (Bubbling)"));
child.addEventListener("click", () => console.log("Child (Capturing)"), true);
Output:
Child (Capturing)
Parent (Bubbling)
Why?
Capturing phase runs top-down: the parent has no capturing listener, so it is skipped. When the phase reaches the child (the target), the child’s true listener fires.
After that, the bubbling phase begins (bottom-up), and the parent’s false listener executes.
How the Flow Actually Works (Step by Step)
Let’s break it down using the diagram:
-
Capturing Phase begins at the
windowobject and moves top → bottom (window → html → body → parent → child).- Only listeners added with
true(or{capture: true}) will execute during this phase.
- Only listeners added with
Target Phase: Once the event reaches the actual clicked element (the target), all listeners on the target element itself run — regardless of whether they were registered with true (capture) or false (bubble).
-
Bubbling Phase starts after the target phase and moves bottom → top (child → parent → body → html → window).
- Only listeners added with
false(default) will execute here.
- Only listeners added with
Important note: Even if you add listeners in capturing mode and there are also other listeners on bubblinh mode, then the bubbling phase still happens unless you call
event.stopPropagation().
Pro Tips for Real Projects
- Use capturing (
true) when you want to handle events before they reach the target (great for preventing default behaviors early). - Most of the time, bubbling (
false) is what you want — it's simpler and sufficient for 90% of use cases. - You can also use the modern object syntax for more control:
element.addEventListener("click", handler, {
capture: true, // same as passing true
once: true, // auto-remove after first trigger
passive: true // performance optimization for scroll/touch
});
Final Thoughts
Event propagation might seem confusing at first, but once you visualize it with the flow (top-down capturing → target → bottom-up bubbling), it becomes incredibly intuitive.
Now you have full control over when your event handlers run. Go ahead and experiment with all four combinations on your own. You'll be amazed at how much power this gives you!

Top comments (0)