# Event Bubbling vs Event Capturing: Understanding DOM Event Propagation in JavaScript

> Understand DOM event propagation in JavaScript. Learn the difference between event bubbling and capturing to control listener execution order.

- Repository: [H5BP/Front-end-Developer-Interview-Questions](https://github.com/h5bp/Front-end-Developer-Interview-Questions)
- Tags: deep-dive
- Published: 2026-03-05

---

**Event bubbling and event capturing represent the two directional phases of DOM event propagation, where capturing travels from the document root down to the target element, and bubbling travels from the target back up to the root, determining execution order of event listeners.**

The `h5bp/Front-end-Developer-Interview-Questions` repository identifies the distinction between event bubbling and event capturing as a fundamental interview topic in [`src/questions/javascript-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/javascript-questions.md), underscoring its importance for frontend developers. Mastering these propagation mechanisms enables precise control over event handling, delegation strategies, and performance optimization in web applications.

## The Three Phases of DOM Event Flow

The DOM event standard defines three distinct phases that occur when an event fires: **capturing** (downward), **target** (arrival), and **bubbling** (upward). According to the source code analysis of interview questions in the repository, understanding this sequence is critical for predicting listener execution order.

### Event Capturing Phase (Root to Target)

During the **capturing phase**, the event originates at the `document` root and propagates downward through the ancestor chain until reaching the target element. Listeners registered with `{ capture: true }` execute during this phase, allowing parent elements to intercept events before they reach their destination.

### Target Phase

The **target phase** occurs when the event arrives at the specific element that triggered the event (the event target). Listeners attached directly to this element run during this phase, regardless of whether they were registered for capturing or bubbling.

### Event Bubbling Phase (Target to Root)

After the target phase, the **bubbling phase** begins, moving upward from the target back to the `document` root. Most standard UI events—such as `click`, `keypress`, and `scroll`—bubble by default, making this phase the primary mechanism for event delegation.

## Registering Listeners for Capturing and Bubbling

The `addEventListener` method accepts a third parameter that determines when the listener executes. As documented in the repository's JavaScript questions section, this API distinction separates the two propagation models.

**Event capturing registration** uses the explicit capture flag:

```javascript
// Capturing listener - fires during downward propagation
element.addEventListener('click', handler, { capture: true });
// Legacy syntax: element.addEventListener('click', handler, true);

```

**Event bubbling registration** uses the default behavior or explicit false:

```javascript
// Bubbling listener - fires during upward propagation (default)
element.addEventListener('click', handler, { capture: false });
// Or simply: element.addEventListener('click', handler);

```

### Execution Order Demonstration

Consider this HTML structure analyzed in the repository examples:

```html
<div id="outer">
  <button id="inner">Click me</button>
</div>

```

When clicking the button, listeners fire in this sequence:

```javascript
const outer = document.getElementById('outer');
const inner = document.getElementById('inner');

// 1. Capturing listener on parent
outer.addEventListener('click', () => {
  console.log('outer capturing'); // Fires first
}, { capture: true });

// 2. Target listener
inner.addEventListener('click', () => {
  console.log('button target'); // Fires second
});

// 3. Bubbling listener on parent
outer.addEventListener('click', () => {
  console.log('outer bubbling'); // Fires third
});

```

**Console output:**

```

outer capturing
button target
outer bubbling

```

## Controlling Event Propagation

Developers can interrupt the event flow at any phase using standard DOM methods. This control is essential for preventing unintended side effects in complex component trees.

### Stopping Propagation

The `event.stopPropagation()` method halts the event immediately, preventing it from continuing through remaining phases:

```javascript
outer.addEventListener('click', (e) => {
  console.log('outer capturing – stop');
  e.stopPropagation(); // Prevents reach to target and bubbling phase
}, { capture: true });

```

When the above listener executes, only `"outer capturing – stop"` logs to the console, demonstrating how capture-phase interception can block child elements from receiving events entirely.

### Immediate Propagation Stop

The `event.stopImmediatePropagation()` method extends this behavior by preventing other listeners on the same element from executing, offering granular control when multiple handlers are registered.

## Practical Applications: Event Delegation

The bubbling phase enables **event delegation**, a performance pattern where a single parent listener manages events for multiple child elements. This technique appears in the repository's conceptual examples and in production code like [`src/_includes/assets/js/app.js`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/_includes/assets/js/app.js).

**Delegated handling using bubbling:**

```javascript
document.body.addEventListener('click', (e) => {
  // Intercepts any click that bubbles up from descendants
  if (e.target.matches('button[data-action]')) {
    console.log('delegated action:', e.target.dataset.action);
  }
});

```

This approach minimizes memory usage by avoiding individual listener attachments to numerous elements, instead relying on the natural upward propagation of click events through the DOM hierarchy.

## Summary

- **Event capturing** moves from `document` root to target, executing listeners registered with `{ capture: true }` before the target receives the event.
- **Event bubbling** moves from target back to `document` root, executing listeners registered with `{ capture: false }` (the default) after target processing.
- **Execution order** follows: capturing listeners → target listeners → bubbling listeners on the same element hierarchy.
- **Propagation control** via `event.stopPropagation()` allows interception at any phase, commonly used in capture-phase filtering or bubbling-phase delegation.
- **Repository source**: The `h5bp/Front-end-Developer-Interview-Questions` project explicitly tests these concepts in [`src/questions/javascript-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/javascript-questions.md) and [`src/_data/questions.json`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/_data/questions.json), reflecting their status as core JavaScript knowledge.

## Frequently Asked Questions

### What is the default behavior of addEventListener regarding event bubbling and event capturing?

By default, `addEventListener` registers handlers for the **bubbling phase** only. When you omit the third parameter or pass `{ capture: false }`, the listener executes during the upward propagation from target to root, which is why most event delegation patterns rely on bubbling rather than capturing.

### Can an event have both capturing and bubbling listeners on the same element?

Yes, the same element can register separate listeners for both phases. If an element in the ancestor chain has listeners registered with `{ capture: true }` and others with `{ capture: false }`, the capturing listener fires when the event travels downward, and the bubbling listener fires when the event travels upward, resulting in two separate executions for the same event instance.

### Why would developers use event capturing instead of bubbling?

Developers use **event capturing** to intercept events early in the propagation cycle, before they reach the target element. This approach suits scenarios requiring global event filtering, input validation, or security controls where parent elements must inspect or block events before child components process them, as implemented in some architectural patterns found in [`src/_includes/assets/js/app.js`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/_includes/assets/js/app.js).

### How does event delegation relate to event bubbling?

**Event delegation** is a direct application of event bubbling, leveraging the fact that most events bubble upward from their target. By attaching a single listener to a common ancestor rather than individual children, developers reduce memory overhead and simplify dynamic content management, since newly added child elements automatically trigger the ancestor's listener through the standard bubbling mechanism.