Event Capturing and Bubbling

Event capturing and bubbling are phases in the DOM event propagation path: capture travels toward the target, and bubbling travels back through ancestors when the event supports it. Understanding the phases helps with listener placement, event delegation, and controlling propagation without confusing it with default-action cancellation.

When an event is dispatched for a node in the DOM, it can travel along the path between that node and its ancestors. This propagation lets a listener on an ancestor respond to activity originating in a descendant.

In the capturing phase, the event moves from the outer ancestors toward the target. In the target phase, listeners on the target are invoked. If the event bubbles, it then travels outward through ancestors in the bubbling phase. Not every event bubbles.

Register an ancestor listener with `addEventListener(type, handler, { capture: true })` to handle the event during capture. The default is `capture: false`, which registers a bubbling-phase listener. A listener on the event’s target runs in the target phase regardless of its capture setting.

`event.target` identifies the event’s originating target, while `event.currentTarget` identifies the node whose listener is currently running. These can differ when an ancestor handles a descendant’s event, as in event delegation.

`stopPropagation()` prevents the event from continuing to other nodes along the propagation path; it does not cancel the event’s default action. `stopImmediatePropagation()` also prevents later listeners on the current node from running. Use `preventDefault()` separately when the goal is to cancel a cancelable default action.

Key points

Interview questions

What is the difference between event capturing and bubbling?

The event first travels through ancestors toward the target during capture, then reaches the target, and may travel back through ancestors during bubbling. A listener on an ancestor can choose the capture phase or, by default, the bubbling phase. The event’s `bubbles` property indicates whether it bubbles. Capture and bubbling are useful for different handling strategies, such as observing events early or delegating child interactions.

How do `event.target` and `event.currentTarget` differ?

`target` is the node where the event originated, while `currentTarget` is the node whose listener is executing. When a child event reaches a listener on a parent, `target` can remain the child while `currentTarget` is the parent. This distinction is central to event delegation, where a shared ancestor handles events from descendants. `currentTarget` is meaningful during listener execution and should not be treated as a permanent reference to the original source.

Compare `stopPropagation()` and `preventDefault()`.

Use `stopPropagation()` when the event should not continue to other nodes on its propagation path. It does not cancel the browser’s default action, such as following a link. Use `preventDefault()` to request cancellation of a cancelable default action; that does not itself stop propagation. `stopImmediatePropagation()` also prevents remaining listeners on the current node from running.

How does event delegation work, and when would you avoid it?

Event delegation places a listener on a shared ancestor and uses bubbling events from descendants to handle them centrally. In the listener, inspect `event.target` and verify that it matches an element the handler supports, often using `closest()` plus a containment check. This can reduce the number of listeners and can work for matching descendants added later. It is unsuitable when the relevant event does not bubble, unless another technique such as capture is appropriate.

When would you use capture rather than bubbling for an ancestor listener?

A capture listener on an ancestor runs while the event travels toward the target, before the target phase. A bubbling listener on that ancestor runs only during the outward phase when the event bubbles. On the target itself, a listener is invoked in the target phase, not an ancestor capture or bubbling phase. Use capture when handling early or when the event’s propagation behavior makes bubbling delegation unsuitable, while checking the event’s semantics before relying on it.