The Capture and Bubble Phases
Understand how events travel through the DOM.
The Capture and Bubble Phases is a free JavaScript Academy lesson on CoddyKit. This is lesson 1 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the JavaScript Academy learning path, and your progress syncs across the web and the CoddyKit app. The JavaScript Academy course includes 4 lessons in total.
Two Trips Through the DOM
When you click an element, the event does not just fire on that element. It travels through the DOM tree in two phases: the capture phase (top down, from document to the target) and the bubble phase (bottom up, from the target back to document).
<div id="outer">
<button id="inner">Click</button>
</div>The Default: Bubbling
By default, addEventListener listens during the bubble phase. A click on the inner button fires its handler first, then the handler on its parent, then the grandparent, and so on up to document.
inner.addEventListener("click", () => console.log("inner"));
outer.addEventListener("click", () => console.log("outer"));
// Click inner -> logs: "inner" then "outer"Opting Into Capture
Pass a third argument of true (or { capture: true }) to listen during the capture phase instead. Capture handlers run top-down, before any bubble handlers.
outer.addEventListener("click", () => console.log("outer capture"), true);
inner.addEventListener("click", () => console.log("inner bubble"));
// Click inner -> "outer capture" then "inner bubble"The Full Order
For a click on #inner with handlers on both phases, the order is: capture phase top-to-bottom, then the target, then bubble phase bottom-to-top.
- document capture
- outer capture
- inner (target)
- outer bubble
- document bubble
event.target vs event.currentTarget
event.target is the element that actually triggered the event (where the click happened). event.currentTarget is the element whose listener is currently running. On a bubbling parent handler these differ.
outer.addEventListener("click", (e) => {
console.log(e.target.id); // "inner" - where click occurred
console.log(e.currentTarget.id); // "outer" - listener owner
});Stopping Propagation
event.stopPropagation() halts the journey: the event will not continue to the next element in the current phase. Parent handlers higher up the tree never run.
inner.addEventListener("click", (e) => {
e.stopPropagation();
console.log("handled here only");
});
outer.addEventListener("click", () => console.log("never runs"));stopImmediatePropagation
stopPropagation() still lets other listeners on the same element run. To also block sibling listeners on the same element, use event.stopImmediatePropagation().
inner.addEventListener("click", (e) => {
e.stopImmediatePropagation();
console.log("first only");
});
inner.addEventListener("click", () => console.log("blocked"));preventDefault Is Different
Do not confuse preventDefault() with stopPropagation(). preventDefault() cancels the browser default action (following a link, submitting a form) but does NOT stop the event from bubbling.
link.addEventListener("click", (e) => {
e.preventDefault(); // do not navigate
// event still bubbles to parents
});Why Capture Is Rare
Most code uses bubbling because it matches intuition: the specific element reacts first, then containers learn about it. Capture is useful when a parent needs to intercept or veto an event before children see it.
Checking the Phase
event.eventPhase tells you which phase is active: 1 capture, 2 at target, 3 bubble. This is rarely needed but helps when debugging complex listener chains.
el.addEventListener("click", (e) => {
console.log(e.eventPhase); // 1, 2, or 3
}, true);Not All Events Bubble
Most UI events (click, input, keydown) bubble. A few do not by default, such as focus, blur, and mouseenter. For those use the bubbling variants (focusin, focusout) or the capture phase.
Quick Check
Test your understanding of event phases.
Recap
Events travel capture (down) then bubble (up). Listeners use bubbling by default; pass true for capture. e.target is the origin, e.currentTarget is the listener owner. Use stopPropagation() to halt travel and preventDefault() to cancel default actions. These two phases are the foundation for event delegation.
Learn JavaScript with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 59
- Lessons
- 200
Frequently Asked Questions
Is the “The Capture and Bubble Phases” lesson free?
Yes — any 3 lessons of the JavaScript Academy learning path, including “The Capture and Bubble Phases”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The JavaScript Academy course includes 4 lessons in total.
What will I learn in “The Capture and Bubble Phases”?
Understand how events travel through the DOM. You practise JavaScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start JavaScript Academy?
No prior experience is required. JavaScript Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.
How long does the “The Capture and Bubble Phases” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this JavaScript Academy lesson?
Yes. Every JavaScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Capture and Bubble Phases
- Event Delegation Pattern
- Dynamic Lists with Delegation
- Custom Events