You're sitting inside a small room (a <button>
), which is inside a bigger room (a <div>
), which is inside an even bigger hall (<body>
).
Now, someone knocks on the innermost room's door (you click the button ). That knock doesn’t just stop there — it echoes outward to the next room, then the next, all the way out.
That’s what event bubbling is in JavaScript.
When an event happens on an element, it first runs the handlers on that element, then on its parent, then all the way up to the document root.
Example
<div id="box">
<button id="btn">Click Me</button>
</div>
document.getElementById("btn").addEventListener("click", function () {
console.log("Button clicked");
});
document.getElementById("box").addEventListener("click", function () {
console.log("Box clicked");
});
When you click the button, both events will run:
Button clicked
Box clicked
Because the event bubbles up from the button to the box.
🧨 What is Event Capturing?
Now imagine the opposite:
The knock starts from the outermost hall and goes inward — the big hall hears it first, then the middle room, then finally the innermost room.
That’s event capturing.
It's the reverse of bubbling. It starts from the top (like window
or document
) and trickles down to the target element.
But by default, JavaScript doesn’t use the capturing phase unless you tell it to.
How to Use Capturing?
element.addEventListener("click", handler, true);
If we update our earlier example:
document.getElementById("btn").addEventListener("click", function () {
console.log("Button clicked");
}, false); // bubbling
document.getElementById("box").addEventListener("click", function () {
console.log("Box clicked");
}, true); // capturing
Now the output becomes:
Box clicked
Button clicked
Because the box heard it first during the capturing phase, then the button during bubbling.
🔄 Three Phases of Event Propagation
Every event goes through three phases :
- Capturing Phase: From
window
down to the parent elements.
- Target Phase: The actual element that was clicked.
- Bubbling Phase: From the clicked element back up to
window
.
But when you add an event listener, you can only choose between capturing or bubbling , not both.
🛑 How to Stop Event Bubbling?
Sometimes you don’t want the event to go up to the parent.
Like, if you have a delete icon inside a card, and clicking delete shouldn’t also trigger the card click.
Use
event.stopPropagation();
Example
document.getElementById("deleteBtn").addEventListener("click", function (e) {
e.stopPropagation();
alert("Delete clicked!");
});
Now the card won’t think it was clicked.
❌ Difference Between stopPropagation()
and preventDefault()
Method |
What It Does |
stopPropagation() |
Stops the event from going up to the parents |
preventDefault() |
Stops the default behavior (like link navigation or form submit) |
Example:
document.querySelector("a").addEventListener("click", function (e) {
e.preventDefault(); // stops page jump
console.log("Link clicked but not opened");
});
🎯 Real-World Use Cases
Let’s see where these concepts are used practically.
✅ 1. Dropdown Close on Outside Click
You have a dropdown menu. When the user clicks anywhere outside the dropdown, it should close.
document.addEventListener("click", function (e) {
if (!dropdown.contains(e.target)) {
dropdown.classList.add("hidden");
}
});
This works because of event bubbling — every click eventually reaches the document.
✅ 2. Form Validation Using Delegation
You have a form with multiple fields. Instead of adding listeners to each field, you add one to the form and let the event bubble.
form.addEventListener("input", function (e) {
if (e.target.matches(".required")) {
validateField(e.target);
}
});
This makes your code cleaner and more efficient.
✅ 3. Nested Buttons or Icons
You have a card with a delete button. Clicking delete shouldn't open the card details.
deleteIcon.addEventListener("click", function (e) {
e.stopPropagation();
removeItem();
});
This prevents the card click handler from running.
✅ 4. Logging User Actions
You can track user actions at a high level instead of attaching listeners everywhere.
document.body.addEventListener("click", function (e) {
console.log("User clicked:", e.target.tagName);
});
🧪 Interview Questions & Answers
Here are some common interview questions you might get — and how to answer them without sounding like a robot.
Q 1. What is Event Bubbling?
Ans
Event bubbling means that when an event happens on an element, it first runs the handler on that element, then bubbles up to its parent, and so on until it reaches the document root.
Q 2. What is Event Capturing?
Ans
Event capturing is the opposite of bubbling. The event starts at the outermost element (like window
) and flows inward to the target element.
Q 3. How do you stop an event from bubbling?
Ans
Using event.stopPropagation()
.
Q 4. What is the difference between stopPropagation
and preventDefault
?
Ans
Q 5. When would you use the capturing phase?
Ans
Rarely. But sometimes, when you want to intercept events before they reach the target, like for global logging or access control.
Q 6. Can you have both bubbling and capturing for the same event?
Ans
Yes, if you attach two different listeners on the same element — one in the capturing phase (true
) and one in bubbling phase (false
).
✅ Summary Table
Concept |
Description |
Event Bubbling |
Runs from child to parent |
Event Capturing |
Runs from parent to child (useCapture: true ) |
stopPropagation |
Stops the event from moving up/down |
preventDefault |
Stops the default browser action |
Real Use Case |
Dropdown close, form validation, nested buttons |
Interview Tip |
Know how the event flows and when to stop it |
So yeah, Event Bubbling and Capturing might sound complex, but once you understand how events flow, it’s super useful for building smarter, more efficient apps.