Facebook Pixel

Event Bubbling, Capturing, and Delegation in JavaScript

DOM events propagate in three phases. Here is how bubbling, capturing, and delegation work.

Event Bubbling, Capturing, and Delegation in JavaScript

DOM events propagate in three phases: capturing, target, and bubbling. Understanding these phases is essential for effective event handling.

The Three Phases

  1. Capturing (downward): from the document down to the target's parent.
  2. Target: the event reaches the target element.
  3. Bubbling (upward): from the target up to the document.

By default, listeners run in the bubbling phase. You can listen in the capturing phase with the third argument to addEventListener:

element.addEventListener("click", handler, true); // capturing element.addEventListener("click", handler, false); // bubbling (default) `` ### Event Bubbling ```html <div id="outer"> <button id="inner">Click</button> </div> `` ```js document.querySelector("#outer").addEventListener("click", () => { console.log("outer clicked"); }); document.querySelector("#inner").addEventListener("click", () => { console.log("inner clicked"); }); // clicking the button logs: "inner clicked", "outer clicked" `` The event bubbles from the button up to the div. Both listeners fire. ### Stopping Propagation ```js document.querySelector("#inner").addEventListener("click", (event) => { event.stopPropagation(); console.log("inner clicked"); }); // clicking the button logs only: "inner clicked" (bubbling stopped) `` ### Event Capturing ```js document.querySelector("#outer").addEventListener("click", () => { console.log("outer capturing"); }, true); // capturing phase document.querySelector("#inner").addEventListener("click", () => { console.log("inner target"); }); // clicking the button logs: "outer capturing", "inner target" `` The outer listener runs first (capturing downward), then the target. ### Event Delegation Instead of adding a listener to each child, add one to the parent: ```js document.querySelector("#list").addEventListener("click", (event) => { if (event.target.matches("li")) { console.log("clicked:", event.target.textContent); } }); `` **Advantages**: - One listener instead of many (memory-efficient). - Works for dynamically added children (no need to add listeners to new elements). - Centralized event handling logic. ### `event.target` vs `event.currentTarget` - `event.target`: the element that triggered the event (the actual clicked element). - `event.currentTarget`: the element the listener is registered on (the element with `addEventListener`). In event delegation, `event.target` is the clicked child; `event.currentTarget` is the parent. ### Events That Do Not Bubble Most events bubble, but some do not: `focus`, `blur`, `load`, `unload`, `scroll` (on elements), `mouseenter`, `mouseleave`. Use `focusin`/`focusout` and `mouseover`/`mouseout` for bubbling versions. ### The Takeaway Events propagate in three phases: capturing (downward), target, and bubbling (upward). By default, listeners run in the bubbling phase. Use `stopPropagation` to prevent further propagation. Use event delegation (one listener on the parent) for efficiency and dynamic children. `event.target` is the clicked element; `event.currentTarget` is the listener element.

When an event on a child element propagates up to its parents. A click on a button inside a div triggers the button's listener, then the div's listener, then the body's, up to the document. By default, listeners run in the bubbling phase.

The downward phase of event propagation, from the document down to the target's parent. Listen in the capturing phase with addEventListener(type, handler, true). By default, listeners run in the bubbling phase (false).

Adding one listener to a parent instead of many listeners to children. Use event.target to determine which child was clicked. This is memory-efficient and works for dynamically added children without needing new listeners.

event.target is the element that triggered the event (the actual clicked element). event.currentTarget is the element the listener is registered on (the element with addEventListener). In delegation, target is the child, currentTarget is the parent.

Call event.stopPropagation() in the handler. This prevents the event from propagating further (both up and down). Note: this does not prevent other listeners on the same element; use event.stopImmediatePropagation() for that.

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.