JavaScript Event Bubbling and Capturing (Trickling)

JavaScript Event Bubbling and Capturing (Trickling)

Event Propagation

JavaScript event propagation occurs in three phases:

  1. Capturing Phase (Trickling) – Events travel from the root (window → document → html → body → ... → target element).

  2. Target Phase – The event reaches the target element where it was originally triggered.

  3. Bubbling Phase – The event propagates back up the DOM (target element → parent → grandparent → document → window).

Event Bubbling

  • Definition: Event bubbling is the default way events propagate in JavaScript. When an event is triggered on an element, it moves upward through the DOM hierarchy to its ancestors.

  • Flow: Events propagate from the target element to its ancestors (child → parent → grandparent → document → window).

  • Key Points:

    • No need to pass a third argument for bubbling; false is the default value.

    • Events "bubble up" like real-world bubbles rising to the surface.

Example Code:

// Event bubbling (default behavior)
document.querySelector("#grandparent").addEventListener(
  "click",
  () => {
    console.log("Grandparent div clicked");
  },
  false // default
);
document.querySelector("#parent").addEventListener(
  "click",
  () => {
    console.log("Parent div clicked");
  },
  false
);
document.querySelector("#child").addEventListener(
  "click",
  () => {
    console.log("Child div clicked");
  },
  false
);

Event Capturing (Trickling)

  • Definition: Event capturing is an alternative propagation method where events travel from the outermost ancestor to the target element.

  • Flow: Events propagate downward through the DOM hierarchy (grandparent → parent → child → target element).

  • Key Points:

    • To enable capturing, pass true as the third argument to addEventListener.

Example Code:

// Event capturing
document.querySelector("#grandparent").addEventListener(
  "click",
  () => {
    console.log("Grandparent div clicked");
  },
  true
);
document.querySelector("#parent").addEventListener(
  "click",
  () => {
    console.log("Parent div clicked");
  },
  true
);
document.querySelector("#child").addEventListener(
  "click",
  () => {
    console.log("Child div clicked");
  },
  true
);

Mixed Propagation Order

  • Behavior: According to W3C standards, capturing happens first, then the target phase, and finally bubbling.

  • Scenarios:

    • true, false, true: Capturing occurs first, then the target phase, and then bubbling begins.

    • true, false, false: Capturing for true listeners, then the target phase, and bubbling for false listeners.

Example Code:

// Mixed propagation order
document.querySelector("#grandparent").addEventListener(
  "click",
  () => {
    console.log("Grandparent div clicked");
  },
  true
);
document.querySelector("#parent").addEventListener(
  "click",
  () => {
    console.log("Parent div clicked");
  },
  false
);
document.querySelector("#child").addEventListener(
  "click",
  () => {
    console.log("Child div clicked");
  },
  true
);

Stopping Event Propagation

  • Method: Use e.stopPropagation() to stop the event from propagating further.

  • Scenarios:

    • Bubbling: Stops propagation from the current element upward.

    • Capturing: Stops propagation before reaching the target element.

Example: Stopping Propagation in Bubbling Phase

// Stopping propagation in bubbling phase
document.querySelector("#grandparent").addEventListener(
  "click",
  () => {
    console.log("Grandparent div clicked");
  },
  false
);
document.querySelector("#parent").addEventListener(
  "click",
  (e) => {
    console.log("Parent div clicked");
    e.stopPropagation(); // Stops event from bubbling further
  },
  false
);
document.querySelector("#child").addEventListener(
  "click",
  (e) => {
    console.log("Child div clicked");
    e.stopPropagation();
  },
  false
);

Example: Stopping Propagation in Capturing Phase

// Stopping propagation in capturing phase
document.querySelector("#grandparent").addEventListener(
  "click",
  (e) => {
    console.log("Grandparent div clicked");
    e.stopPropagation();
  },
  true
);
document.querySelector("#parent").addEventListener(
  "click",
  (e) => {
    console.log("Parent div clicked");
    e.stopPropagation();
  },
  true
);
document.querySelector("#child").addEventListener(
  "click",
  (e) => {
    console.log("Child div clicked");
    e.stopPropagation();
  },
  true
);

Summary

  1. Bubbling: Propagation moves upward from the target element to ancestors.

  2. Capturing: Propagation moves downward from the root to the target element.

  3. Target Phase: The event is at the target element where it was triggered.

  4. Order: Capturing → Target → Bubbling.

  5. Stopping Propagation: e.stopPropagation() halts the event in its current phase.

  6. Best Practices:

    • Use capturing when handling high-level events first.

    • Use bubbling for default behavior and component-based events.

    • Stop propagation only when necessary to avoid unintended side effects.


🎥 For More Clarity

Watch this video for a better understanding: Event Bubbling & Capturing Explained