Event Buddling and Capturing

Overview

  1. Capturing phase – the event goes down to the element.

  2. Target phase – the event reached the target element.

  3. Bubbling phase – the event bubbles up from the element.

Buddling

  • 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.

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="console.log('form')">FORM
  <div onclick="console.log('div')">DIV
    <p onclick="console.log('p')">P</p>
  </div>
</form>

Output:
p div form

Targeting

  • The most deeply nested element that caused the event is called a target element, accessible as event.target.

  • Note the differences from event.currentTarget:

    • event.target – is the “target” element that initiated the event, it doesn’t change through the bubbling process.

    • event.currentTarget – is the “current” element, the one that has a currently running handler on it.

  • In form.onclick handler:

    • event.currentTarget is the <form> element, because the handler runs on it.

    • event.target is the actual element inside the form that was clicked.

  • event.stopPropagation() stop event budding up to parent element

Capturing

  • To catch an event on the capturing phase, we need to set the handler capture option to true:

elem.addEventListener(..., {capture: true})
// or, just "true" is an alias to {capture: true}
elem.addEventListener(..., true)
  • Example

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form>FORM
  <div>DIV
    <p>P</p>
  </div>
</form>

<script>
  for(let elem of document.querySelectorAll('*')) {
    elem.addEventListener("click", e => console.log(`Capturing: ${elem.tagName}`), true);
    elem.addEventListener("click", e => console.log(`Bubbling: ${elem.tagName}`));
  }
</script>

// output:
Capturing: html
Capturing: form
Capturing: div
Capturing: p
Buddling: p
Buddling: div
Buddling: form
Buddling: html

Custom Event

const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

// Create a new event, allow bubbling, and provide any data you want to pass to the "detail" property
const eventAwesome = new CustomEvent("awesome", {
  bubbles: true,
  detail: { text: () => textarea.value },
});

// The form element listens for the custom "awesome" event and then consoles the output of the passed text() method
form.addEventListener("awesome", (e) => console.log(e.detail.text()));

// As the user types, the textarea inside the form dispatches/triggers the event to fire, and uses itself as the starting point
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));

Reference

Last updated

Was this helpful?