What is Event Bubbling?
Event bubbling in JavaScript is a mechanism in the Document Object Model (DOM) where an event, triggered on a specific element, propagates upwards through its parent elements in the DOM hierarchy.
<body>
<div>
<button>Click Me!</button>
</div>
</body>
The button is a child of the span, which in turn is a child of the div, and the div is a child of the body.
<element>.addEventListener(<eventName>,
<callbackFunction>, {capture : boolean});
element: The element to which an event listener is attached.
eventName: It can be 'click','key up','key down' etc. events.
callbackFunction: This function fires after the event happened.
{capture: boolean}: It tells whether the event will be in the capture phase or in the bubbling phase (optional)
<body>
<div>
<h2>Welcome To Kithi's DEV Community</h2>
<div id="grandparent">GrandParent
<div id="parent">Parent
<div id="child">Child</div>
</div>
</div>
</div>
<script>
const grandParent = document.getElementById("grandparent");
const parent = document.getElementById("parent");
const child = document.getElementById("child");
grandParent.addEventListener("click", (e) => {
console.log("GrandParent");
}, { capture: false });
parent.addEventListener("click", (e) => {
console.log("Parent");
}, { capture: false });
child.addEventListener("click", (e) => {
console.log("Child");
}, { capture: false });
</script>
</body>
Output:
Child
Parent
GrandParent
When we clicked on the div with the child as its id, we should get the output as 'child' on our console. But unexpectedly, we are receiving a different output even we have not clicked on divs with parent and grandparent as their id. The concept of event bubbling comes into the picture. The child div lies inside the parent div as well as in the grandparent div. So, when the child div clicked, we indirectly clicked on both parent div and grandparent div. Thus, propagation is moving from inside to outside in the DOM or we can say events are getting bubble up.
Therefore, the process of propagating from the closest element to the farthest away element in the DOM (Document Object Modal) is called event bubbling.
In the above example, let us change the value of the third parameter of addEventListener() and see what changes will be made in the output.
<body>
<div>
<h2>Welcome To Kithi's DEV Community</h2>
<div id="grandparent">GrandParent
<div id="parent">Parent
<div id="child"> Child</div>
</div>
</div>
</div>
<script>
const grandParent = document.getElementById("grandparent");
const parent = document.getElementById("parent");
const child = document.getElementById("child");
// Changing value of capture parameter as 'true'
grandParent.addEventListener("click", (e) => {
console.log("GrandParent");
}, { capture: true });
parent.addEventListener("click", (e) => {
console.log("Parent");
}, { capture: true });
child.addEventListener("click", (e) => {
console.log("Child");
}, { capture: true });
</script>
</body>
Output:
GrandParent
Parent
Child
It's clearly visible that the ancestor divs of the child div were printing first and then the child div itself. So, the process of propagating from the farthest element to the closest element in the DOM is called event capturing. Both terms are just opposite of each other.
How to stop event bubbling and event capturing?
In the above example, we can see a parameter "e" (or sometimes called as "event") in the callback function of addEventListener(). It is an event object which automatically defines when we add an event listener to an element. This object 'e' has a function called stopPropagation() which helps to prevent this annoying behavior.
<body>
<div>
<h2>Welcome To Kithi's DEV Community</h2>
<div id="grandparent">GrandParent
<div id="parent">Parent
<div id="child"> Child</div>
</div>
</div>
</div>
<script>
const grandParent = document.getElementById("grandparent");
const parent = document.getElementById("parent");
const child = document.getElementById("child");
grandParent.addEventListener("click", (e) => {
console.log("GrandParent bubbling");
});
parent.addEventListener("click", (e) => {
e.stopPropagation(); //syntax to stop event bubbling
console.log("Parent bubbling");
});
child.addEventListener("click", (e) => {
console.log("Child bubbling");
});
</script>
</body>
Output:
Child bubbling
Parent bubbling
if we clicked on child div, the propagation is stopped on parent div and does not move to grandparent div. Hence, the event bubbling is prevented.
Note:
The event capturing can also be prevented using the same way.
Conclusion:
Event capturing means propagation of event is done from ancestor elements to child element in the DOM while event bubbling means propagation is done from child element to ancestor elements in the DOM.
The event capturing occurs followed by event bubbling.
If {capture: true} ,event capturing will occur else event bubbling will occur.
Both can be prevented by using the stopPropagation() method.
Top comments (0)