JavaScript Fundamentals / Events

Event Bubbling/Capturing

In the DOM (Document Object Model), when an event occurs on an element, it travels through the DOM in a specific order. This is known as event propagation. It travels through the DOM in phases.

✅ Three Event Phases

1️⃣ Capturing Phase (Event goes DOWN the tree)

→ From window → document → <html> → <body> → parent elements → target

2️⃣ Target Phase

→ Event reaches the actual clicked element

3️⃣ Bubbling Phase (Event goes UP the tree)

→ From target element → parent → <body> → <html> → document


🔽 Event Capturing (Trickling Phase)

  • Event is handled from outermost to innermost

  • Rarely used but available

How to enable capturing:

element.addEventListener('click', handler, true);

✅ The true makes the listener run during capturing phase


🔼 Event Bubbling (Default Behavior)

  • Event is handled from innermost to outermost

  • Default phase in JavaScript

Bubbling example:

<div id="parent">
  <button id="child">Click Me</button>
</div>

<script>
  document.getElementById('parent').addEventListener('click', () => {
    console.log('Parent clicked');
  });

  document.getElementById('child').addEventListener('click', () => {
    console.log('Child clicked');
  });
</script>
Child clicked
Parent clicked

✋ Stopping the Event Flow

stopPropagation()

Stops event from continuing to bubble or capture.

<div id="parent">
    Parent Div
    <button id="child">Click Child Button</button>
</div>

<script>
  const parent = document.getElementById('parent');
  const child = document.getElementById('child');

  parent.addEventListener('click', () => {
    console.log('Parent clicked');
  });

  child.addEventListener('click', (e) => {
    e.stopPropagation(); // ✅ prevents bubbling to parent
    console.log('Child clicked');
  });
</script>
Child clicked

✅ Parent does NOT log

✅ Because stopPropagation() stops the event from bubbling up

Parent clicked

✅ Works normally

✅ Because no child event was triggered


stopImmediatePropagation()

  • Stops bubbling/capturing, just like stopPropagation()

  • AND stops other event listeners on the SAME element from running

button.addEventListener('click', () => {
  console.log('Listener 1');
});

button.addEventListener('click', (e) => {
  e.stopImmediatePropagation();
  console.log('Listener 2');
});

button.addEventListener('click', () => {
  console.log('Listener 3');
});

// Output : Listener 2

Why?

  • Listener 2 runs first

  • It calls stopImmediatePropagation()

  • So:

    ❌ No more listeners on button

    ❌ Event does NOT bubble up

    ✅ Only Listener 2 executes


🆚 Quick difference

Method

Stops bubbling?

Stops other listeners on same element?

stopPropagation()

✅ Yes

❌ No

stopImmediatePropagation()

✅ Yes

✅ Yes


🔍 Quick Comparison

Feature

Capturing

Bubbling

Direction

Top → Target

Target → Top

Default?

❌ No

✅ Yes

Enable using

addEventListener(..., true)

addEventListener(..., false)

Common usage

Rare

Very common (delegation)