DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
  1. Home
  2. Articles
  3. Event Propagation: Capturing, Bubbling, and Delegation Deep Dive
XLinkedInReddit

Event Propagation: Capturing, Bubbling, and Delegation Deep Dive

Deep dive into event propagation — capturing, bubbling, delegation, stopPropagation, and React's synthetic event system.

D
DevPrep Team
February 10, 2026·4 min read·0
Table of Contents
  • 1. Architectural Foundation: The Event Lifecycle
  • The Phases
  • 2. Advanced Propagation Control
  • stopImmediatePropagation()
  • The "Global Analytics" Pitfall
  • 3. High-Performance Event Delegation
  • The closest() Pattern
  • Passive Event Listeners
  • 4. Framework Internals: The React 17+ Evolution
  • The Great Migration (v16 vs v17)
  • Synthetic Event Pooling
  • 5. The Shadow DOM: Encapsulation vs. Visibility
  • Event Retargeting
  • Crossing the Boundary
  • Debugging the Path
  • 6. Edge Cases & Interview "Gotchas"
  • 7. System Design Challenge: The Global Event Bus

1. Architectural Foundation: The Event Lifecycle

Standard UI interaction is not just a bubble; it is a precisely orchestrated sequence governed by the W3C DOM Level 3 Events specification.

The Phases

  1. Capture Phase: The event travels from the window down to the target’s parent.

  2. Target Phase: The event reaches the event.target. Note: At the target, listeners fire in the order they were registered, regardless of the capture flag (though some modern browsers have optimized this).

  3. Bubble Phase: The event travels back up the tree.

Staff Perspective: Why does Capture exist? It was Netscape’s model, while Bubbling was IE’s. The W3C combined them. Practically, we use Capture for "gatekeeping" logic—intercepting events before they reach a complex sub-tree to prevent interaction or perform logging without the child knowing.


2. Advanced Propagation Control

While stopPropagation() is common, Staff engineers must understand the side effects of "killing" an event.

stopImmediatePropagation()

If an element has three listeners, stopPropagation() stops the event from reaching the parent. stopImmediatePropagation() stops the event from reaching the other two listeners on that same element.

The "Global Analytics" Pitfall

Scenario: You use e.stopPropagation() on a button to prevent a parent modal from closing.

The Bug: Your company’s global tracking library (GTM/Amplitude) is likely attached to document or window. Because you stopped propagation, the button click is never tracked, leading to incorrect "conversion" data.

Staff Solution: Use "State-based" logic or check e.defaultPrevented instead of stopping the event entirely, allowing it to reach global trackers.


3. High-Performance Event Delegation

Delegation is the Staff Engineer’s tool for memory management and DOM stability.

The closest() Pattern

Avoid brittle tagName checks. Use .closest() to handle nested elements (like icons inside buttons) correctly.

JavaScript

// High-performance container-level handler
const handleListAction = (event) => {
  // Find the logical "Row" regardless of which nested span/icon was clicked
  const actionSource = event.target.closest('[data-action]');
  
  if (!actionSource || !event.currentTarget.contains(actionSource)) return;

  const actionType = actionSource.dataset.action;
  performAction(actionType);
};

// Attached once at the container level
document.querySelector('#large-data-grid').addEventListener('click', handleListAction);

Passive Event Listeners

For high-frequency events like wheel or touchstart, the browser’s main thread often waits to see if you call preventDefault() before it allows the page to scroll. This causes Scroll Jank.

JavaScript

// Staff-level optimization: Tell the browser "I won't block scrolling"
window.addEventListener('touchstart', onTouch, { passive: true });

This single flag can be the difference between a "laggy" mobile experience and a 60fps fluid UI.


4. Framework Internals: The React 17+ Evolution

React does not use native browser delegation directly on elements. It uses SyntheticEvents.

The Great Migration (v16 vs v17)

  • React 16: All events were delegated to document.

  • React 17/18/19: Events are delegated to the Root DOM Container (e.g., <div id="root">).

Why this matters at FAANG: If you are running a "Micro-Frontend" architecture where one version of React is embedded inside another, React 16’s document delegation would cause the "Inner" React app’s e.stopPropagation() to fail because the event had already reached the document. React 17+ fixes this by scoping events to the app's root.

Synthetic Event Pooling

Note: This was removed in React 17.

Previously, React reused event objects to save memory. You had to call e.persist() to use the event in an async function. A Staff engineer should know this history to maintain legacy enterprise codebases.


5. The Shadow DOM: Encapsulation vs. Visibility

When working with Web Components, standard propagation "breaks" to protect encapsulation.

Event Retargeting

If a click happens inside a Shadow Root, and it bubbles out to the main document, the event.target is reset to the Host Element. The outside world shouldn't know about the private <span> inside your custom <fancy-button>.

Crossing the Boundary

To make a custom event cross the Shadow DOM line, you must set composed: true.

JavaScript

// Inside a Web Component
this.dispatchEvent(new CustomEvent('data-change', {
  bubbles: true,   // Move up the tree
  composed: true,  // Cross the Shadow DOM boundary
  detail: { id: 123 }
}));

Debugging the Path

When propagation gets weird in a Shadow DOM environment, event.target is useless. Use event.composedPath()—it returns an array of every node the event touched, even those inside "Open" shadow roots.


6. Edge Cases & Interview "Gotchas"

Event

Bubbles?

Staff Note

focus / blur

No

Use focusin / focusout for delegation.

mouseenter / mouseleave

No

Use mouseover / mouseout if you need to delegate.

scroll

No

Attached to elements, does not bubble (except on window).

submit

Yes

Crucial for "Form Auto-save" delegation logic.


7. System Design Challenge: The Global Event Bus

In a Staff interview, you might be asked: "Design a system that tracks every user click across 50 different independent teams' widgets without manual instrumentation."

The Staff Solution:

  1. Top-level Capture Listener: Attach a single click listener to window in the Capture phase.

  2. Schema-Driven Metadata: Look for data-analytics-* attributes using e.composedPath().

  3. Non-blocking IO: Buffer the events and use requestIdleCallback or navigator.sendBeacon() to offload the data without blocking the UI thread

Related Articles

MediumFrontend Engineering

System Design #12: Design a Multi-Step Form Wizard

7 min read
MediumFrontend Engineering

Mastering Senior-Level JavaScript Interview Concepts

2 min read
MediumFrontend Engineering

System Design #9: Design a Collaborative Text Editor

9 min read

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Table of Contents

  • 1. Architectural Foundation: The Event Lifecycle
  • The Phases
  • 2. Advanced Propagation Control
  • stopImmediatePropagation()
  • The "Global Analytics" Pitfall
  • 3. High-Performance Event Delegation
  • The closest() Pattern
  • Passive Event Listeners
  • 4. Framework Internals: The React 17+ Evolution
  • The Great Migration (v16 vs v17)
  • Synthetic Event Pooling
  • 5. The Shadow DOM: Encapsulation vs. Visibility
  • Event Retargeting
  • Crossing the Boundary
  • Debugging the Path
  • 6. Edge Cases &amp; Interview "Gotchas"
  • 7. System Design Challenge: The Global Event Bus

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.