JavaScript Event Bubbling and Capturing (Trickling)

Hi, π I'm Vinay Patel I am a Software Developer with a passion for building scalable and high-performance applications.
Event Propagation
JavaScript event propagation occurs in three phases:
Capturing Phase (Trickling) β Events travel from the root (
window β document β html β body β ... β target element).Target Phase β The event reaches the target element where it was originally triggered.
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;
falseis 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
trueas the third argument toaddEventListener.
- To enable capturing, pass
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 fortruelisteners, then the target phase, and bubbling forfalselisteners.
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
Bubbling: Propagation moves upward from the target element to ancestors.
Capturing: Propagation moves downward from the root to the target element.
Target Phase: The event is at the target element where it was triggered.
Order: Capturing β Target β Bubbling.
Stopping Propagation:
e.stopPropagation()halts the event in its current phase.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




