What is Event bubbling and Event Capturing in JavaScript ?
Last Updated :
14 Sep, 2021
Event bubbling and event capturing are the two interesting concepts of JavaScript. Before diving deep into these fascinating concepts, let us first know about what an event listener is? An event listener is basically a function that waits for an event to occur. That event can be anything like a mouse click event, submitting a form, pressing keys of a keyboard, etc.
An event listener contains three parameters and it can be defined using the following syntax.
<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)
Example 1: Let's take an example to understand event bubbling and event capturing.
HTML
<!DOCTYPE html>
<html>
<head>
<script src=
"https://code.jquery.com/jquery-3.6.0.min.js">
</script>
<style>
div {
color: white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h2 {
color: black;
}
#grandparent {
background-color: green;
width: 300px;
height: 300px;
}
#parent {
background-color: blue;
width: 200px;
height: 200px;
}
#child {
background-color: red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div>
<h2>Welcome To GFG</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>
</html>
Output:
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.
Example 2: 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.
HTML
<!DOCTYPE html>
<html>
<head>
<style>
div {
color: white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h2 {
color: black;
}
#grandparent {
background-color: green;
width: 300px;
height: 300px;
}
#parent {
background-color: blue;
width: 200px;
height: 200px;
}
#child {
background-color: red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div>
<h2>Welcome To GFG</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>
</html>
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.
Example 3: Let's play around more with the code for better understanding.
HTML
<!DOCTYPE html>
<html>
<head>
<style>
div {
color: white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h2 {
color: black;
}
#grandparent {
background-color: green;
width: 300px;
height: 300px;
}
#parent {
background-color: blue;
width: 200px;
height: 200px;
}
#child {
background-color: red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div>
<h2>Welcome To GFG</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");
document.addEventListener("click", (e) => {
console.log("Document capturing");
}, { capture: true });
grandParent.addEventListener("click", (e) => {
console.log("GrandParent capturing");
}, { capture: true });
parent.addEventListener("click", (e) => {
console.log("Parent capturing");
}, { capture: true });
child.addEventListener("click", (e) => {
console.log("Child capturing");
}, { capture: true });
document.addEventListener("click", (e) => {
console.log("Document bubbling");
}, { capture: false });
grandParent.addEventListener("click", (e) => {
console.log("GrandParent bubbling");
}, { capture: false });
parent.addEventListener("click", (e) => {
console.log("Parent bubbling");
}, { capture: false });
child.addEventListener("click", (e) => {
console.log("Child bubbling");
}, { capture: false });
</script>
</body>
</html>
Output: If we clicked on the div with id child, then this will be the output.
We can see that the event capturing of event listeners happened first and then the event bubbling happened. This means the propagation of event listeners first goes from outside to inside and then from inside to outside in the DOM.
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.
Example 4: Let's see what will happen when we will click on child div in the below code.
HTML
<!DOCTYPE html>
<html>
<head>
<style>
div {
color: white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h2 {
color: black;
}
#grandparent {
background-color: green;
width: 300px;
height: 300px;
}
#parent {
background-color: blue;
width: 200px;
height: 200px;
}
#child {
background-color: red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div>
<h2>Welcome To GFG</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>
</html>
Output:
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.
Important points to remember:
- If we do not mention any third parameter in addEventListener(), then by default event bubbling will happen.
- Event bubbling and event capturing happen only when the element and it's all ancestors have the same event listener (in our case, 'click' event) attach to them.
Conclusion: We have learned about event bubbling and event capturing and these are some key points.
- 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.
Similar Reads
Non-linear Components In electrical circuits, Non-linear Components are electronic devices that need an external power source to operate actively. Non-Linear Components are those that are changed with respect to the voltage and current. Elements that do not follow ohm's law are called Non-linear Components. Non-linear Co
11 min read
JavaScript Tutorial JavaScript is a programming language used to create dynamic content for websites. It is a lightweight, cross-platform, and single-threaded programming language. It's an interpreted language that executes code line by line, providing more flexibility.JavaScript on Client Side: On the client side, Jav
11 min read
Web Development Web development is the process of creating, building, and maintaining websites and web applications. It involves everything from web design to programming and database management. Web development is generally divided into three core areas: Frontend Development, Backend Development, and Full Stack De
5 min read
Spring Boot Tutorial Spring Boot is a Java framework that makes it easier to create and run Java applications. It simplifies the configuration and setup process, allowing developers to focus more on writing code for their applications. This Spring Boot Tutorial is a comprehensive guide that covers both basic and advance
10 min read
React Interview Questions and Answers React is an efficient, flexible, and open-source JavaScript library that allows developers to create simple, fast, and scalable web applications. Jordan Walke, a software engineer who was working for Facebook, created React. Developers with a JavaScript background can easily develop web applications
15+ min read
React Tutorial React is a powerful JavaScript library for building fast, scalable front-end applications. Created by Facebook, it's known for its component-based structure, single-page applications (SPAs), and virtual DOM,enabling efficient UI updates and a seamless user experience.Note: The latest stable version
7 min read
JavaScript Interview Questions and Answers JavaScript is the most used programming language for developing websites, web servers, mobile applications, and many other platforms. In Both Front-end and Back-end Interviews, JavaScript was asked, and its difficulty depends upon the on your profile and company. Here, we compiled 70+ JS Interview q
15+ min read
Class Diagram | Unified Modeling Language (UML) A UML class diagram is a visual tool that represents the structure of a system by showing its classes, attributes, methods, and the relationships between them. It helps everyone involved in a projectâlike developers and designersâunderstand how the system is organized and how its components interact
12 min read
Backpropagation in Neural Network Back Propagation is also known as "Backward Propagation of Errors" is a method used to train neural network . Its goal is to reduce the difference between the modelâs predicted output and the actual output by adjusting the weights and biases in the network.It works iteratively to adjust weights and
9 min read
3-Phase Inverter An inverter is a fundamental electrical device designed primarily for the conversion of direct current into alternating current . This versatile device , also known as a variable frequency drive , plays a vital role in a wide range of applications , including variable frequency drives and high power
13 min read