Behavior: Events are like gossip - they start at the target and travel up the family tree, telling everyone what happened.

Main Points:

  1. Bubbling (Default): Click a child → parent hears about it → grandparent hears about it → keeps going up

    javascript

    <div onclick="alert('parent')">
      <button onclick="alert('child')">Click</button>
    </div>
    // Result: "child" then "parent"

Bubbling

The bubbling principle is simple.

When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.

Let’s say we have 3 nested elements FORM > DIV > P with a handler on each of them:

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>
 
<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

A click on the inner <p> first runs onclick:

  1. On that <p>.
  2. Then on the outer <div>.
  3. Then on the outer <form>.
  4. And so on upwards till the document object.

So if we click on <p>, then we’ll see 3 alerts: p → div → form.

The process is called “bubbling”, because events “bubble” from the inner element up through parents like a bubble in the water.

  1. event.target vs this: Target = where you actually clicked, this = who’s currently handling it

    javascript

    div.onclick = function(e) {
      console.log(e.target);        // <button> (what you clicked)
      console.log(this);            // <div> (who's handling it now)
    }
  2. Capturing (Rare): Reverse bubbling - parents hear first, then children

    javascript

    elem.addEventListener('click', handler, true); // Capturing mode
    // Goes: document → html → body → div → target

Interview Gotchas:

  • event.stopPropagation() kills bubbling but other handlers on same element still run
  • event.stopImmediatePropagation() kills everything - no more handlers period
  • Capturing requires addEventListener(..., true) - can’t use onclick

Simple Rules:

stopPropagation():

  • Stops event from going to parent elements
  • Other handlers on SAME element still run
  • Like telling your siblings but not your parents

stopImmediatePropagation():

  • Stops event from going to parent elements
  • Stops ALL remaining handlers on same element
  • Like shutting everyone up immediately

addEventListener with true:

  • Catches events on the way DOWN (capturing)
  • onclick and HTML attributes can’t do this
  • They only work on the way UP (bubbling)

Behavior Examples:

javascript

// stopPropagation - siblings still talk
button.addEventListener('click', () => console.log('1'));
button.addEventListener('click', (e) => { console.log('2'); e.stopPropagation(); });
button.addEventListener('click', () => console.log('3'));
// Result: 1, 2, 3 (but parent never hears)
 
// stopImmediatePropagation - silence NOW
button.addEventListener('click', () => console.log('1'));
button.addEventListener('click', (e) => { console.log('2'); e.stopImmediatePropagation(); });
button.addEventListener('click', () => console.log('3')); // NEVER RUNS
// Result: 1, 2 (everything stops)

Bottom Line: Regular stop = “don’t tell parents”, Immediate stop = “don’t tell anyone else”

Bottom Line: Events bubble up by default (child tells parent tells grandparent). You usually want this behavior - don’t stop it unless you have a real reason. Think of it as automatic event delegation


Capturing Phase (Document → Target):

  • Events ALWAYS travel down first, but handlers DON’T run by default
  • To catch during capturing: addEventListener('click', handler, true)
  • Without true, handlers are “deaf” during this phase

Target Phase:

  • When event reaches the actual clicked element
  • Both capturing AND bubbling handlers run here (if any exist)
  • This is where most action happens

Bubbling Phase (Target → Document):

  • YES, by default ALL handlers trigger going back up
  • onclick, addEventListener('click', handler) - these run during bubbling
  • No special param needed - this is the default behavior

What You Missed:

  1. Most handlers run during BUBBLING, not capturing

    javascript

    div.onclick = handler;                    // Bubbling (default)
    div.addEventListener('click', handler);   // Bubbling (default)
    div.addEventListener('click', handler, true); // Capturing only
  2. Target phase runs BOTH types:

    javascript

    button.addEventListener('click', () => console.log('capturing'), true);
    button.addEventListener('click', () => console.log('bubbling'), false);
    // Click button: logs "capturing" then "bubbling"
  3. Journey visualization:

    CAPTURING: document → html → body → div → button (only if capture:true)
    TARGET: button runs both capturing & bubbling handlers
    BUBBLING: button → div → body → html → document (default behavior)
    

Interview Gotcha: People think only target runs - WRONG! Parent handlers run too during bubbling unless stopped.

Bottom Line: Capturing = silent journey down, Target = both types run, Bubbling = noisy journey up (default).