0Pricing
JavaScript Academy · Lesson

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 — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the JavaScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

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.

Frequently asked questions

Is the “The Capture and Bubble Phases” lesson free?

Yes — the full text of “The Capture and Bubble Phases” is free to read here on the web, and the JavaScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the JavaScript Academy course, upgrade to CoddyKit PRO.

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; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

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

  1. The Capture and Bubble Phases
  2. Event Delegation Pattern
  3. Dynamic Lists with Delegation
  4. Custom Events
← Back to JavaScript Academy