Open In App

What is Event bubbling and Event Capturing in JavaScript ?

Last Updated : 14 Sep, 2021
Improve
Improve
Like Article
Like
Save
Share
Report

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=
    </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

What is Event Bubbling and Capturing in JavaScript ?
Events are a fundamental construct of the modern web. They are a special set of objects that allow for signaling that something has occurred within a website. By defining Event listeners, developers can run specific code as the events happen. This allows for implementing complex control logic on a web application. Every time you press a key, click
6 min read
What is Event propagation, capturing, bubbling ?
In this article, we will learn about Event Propagation, Capturing, and Bubbling. Event Propagation determines in which order the elements receive the event. There are two ways to handle this event propagation order of HTML DOM is Event Bubbling and Event Capturing. For example, suppose there are three components namely component1, component2, compo
3 min read
Event bubbling in JavaScript
Event bubbling is a method of event propagation in the HTML DOM API when an event is in an element inside another element, and both elements have registered a handle to that event. It is a process that starts with the element that triggered the event and then bubbles up to the containing elements in the hierarchy. In event bubbling, the event is fi
2 min read
What is Event Bubbling ?
Event bubbling can be defined as a phase of Event propagation in which if an event occurs on a particular element will propagate or bubble up to the ancestor or the parent elements in the DOM hierarchy. By default, all the events bubble up to their ancestors. For example, suppose you are given three different elements A(Grand parent), B(Parent), an
1 min read
Difference between Event Bubling & Event Capturing ?
Event BubblingEvent bubbling is the default behavior in which an event triggered on a nested element propagates up through its ancestors in the DOM hierarchy, allowing each ancestor to respond to the event. Event Capturing Event capturing is the opposite of event bubbling, where the event is captured on the outermost ancestor first, and then it pro
1 min read
Less.js Nested At-Rules and Bubbling
Less.js allows you to nest up different at-rules like @media and @supports and it can be done in the same way as the selectors and normal CSS rules like it is shown in nested rules in LESS. The selector directive is set at the top and the various at-rules can be set into a relative order inside the ruleset after compilation the relative order stays
4 min read
What is Event Capturing ?
Event Capturing is also one of the Event Propagation phases. It is also known as Event Trickling. It is the opposite of the event bubbling phase. In event bubbling where the event bubbles out from the target element to its ancestors in the DOM hierarchy, here it will go down through the ancestor to the target element. This downward propagation of t
1 min read
JavaScript for Capturing mouse positions after every given interval
The JavaScript language was initially created for web browsers. Since then, it evolved and became a language with many uses and platforms. It lets us interact with the browser using events. Events are signals that something has happened. When JavaScript is used in HTML pages, JavaScript can react to these events. To react to events we can assign a
3 min read
Capturing Time in React
In this article, we will learn how to simply display the current time in our ReactJs application. We will use Date() method. We will create a new object with Date(), which comes along with some predefined methods such as getMonth() that shows the month, getHour() shows the current hour, getTime() that shows in milliseconds the time is calculated fr
2 min read
What is the use of the Event.preventDefault() method in Event Handling in JavaScript ?
The Event.preventDefault() method in JavaScript is used within event handlers to prevent the default behavior associated with an event from taking place. When an event occurs, such as a click on a link or the submission of a form, there is often a default action associated with that event. preventDefault() allows developers to stop this default beh
1 min read