Event Bubbling and Capturing in JavaScript

In JavaScript, the concept of event propagation is referred to as 'Event Flow'. Event Flow describes the sequence or arrangement in which a specific web page processes an event. Consequently, in JavaScript, the event flow mechanism is influenced by three key components, which are:

Event Capturing

Event Target

Event Bubbling

In this segment, we will explore and examine two key concepts: event bubbling and event capturing. Our approach will be to engage with these ideas in a practical manner, tackling each one sequentially.

Event Bubbling

When creating a webpage or website using JavaScript, the principle of event bubbling comes into play, wherein event handlers are triggered when one element is encapsulated within another element, and both participate in the same event. This approach is referred to as Event Bubbling. As such, during the event flow process for a web page, event bubbling is implemented. We can interpret event bubbling as a series of invocations of the event handlers when a nested element exists within another element, with both elements having listeners registered for the identical event. The invocation process commences from the innermost element, propagating through its parent elements and encompassing all ancestor elements until it reaches the topmost element, thereby executing calls from bottom to top.

Example of Event Bubbling

Let us examine the following example to gain insight into the principle of Event Bubbling:

Example

<!DOCTYPE html>

<html>

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width">

  <title>Event Bubbling</title>

</head>

<body>

  <div id="p1">

    <button id="c1">I am child button</button>

  </div>

  

  <script>

    var parent = document.querySelector('#p1');

      parent.addEventListener('click', function(){

        console.log("Parent is invoked");

      });



   var child = document.querySelector('#c1');

      child.addEventListener('click', function(){

        console.log("Child is invoked");

      });

  </script>

</body>

</html>

Output:

Explanation of Code:

  • The above code is a HTML and JavaScript based code.
  • We have used a div tag having div id = p1 and within div we have nested a button having button id = c1.
  • Now, within the JavaScript section, we have assigned the html elements (p1 and c1) using the querySelector function to the variable parent and child.
  • After that, we have created and included an event which is the click event to both div element and child button. Also created two functions that will help us to know the sequence order of the execution of the parent and child. It means if the child event is invoked first, "child is invoked" will be printed otherwise "parent is invoked" will get printed.
  • Thus, when the button is clicked, it will first print "child is invoked" which means that the function within the child event handler executes first. Then it moves to the invocation of the div parent function.

The series of occurrences has transpired as a result of the principle of event bubbling. Consequently, this is how event bubbling occurs.

The progression of events can also be illustrated through the following flow chart:

This indicates that when a user presses the button, the click event propagates in the following sequence, moving from the bottom to the top.

Stopping Bubbling

The process of bubbling commences at the target element and ascends towards the root, meaning it initiates from a child element and progresses directly upward to its parent elements. However, a handler has the authority to terminate this bubbling process once the event has been fully handled. In JavaScript, this is accomplished using the event.stopPropagation function.

For example:

Example

<!DOCTYPE html>

<html>

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width">

  <title>Event Bubbling</title>

</head>

<body>

  <div id="p1">

    <button id="c1" onclick="event.stopPropagation()">I am child</button>

  </div>

 	<script>

    var parent = document.querySelector('#p1');

      parent.addEventListener('click', function(){

        console.log("Parent is invoked");

      });

    var child = document.querySelector('#c1');

      child.addEventListener('click', function(){

        console.log("Child is invoked");

      });

  </script>

</body>

</html>

In the code provided above, clicking the button will not trigger any action since the event.stopPropagation method is called. This prevents the parent function from executing.

Note: The event.stopPropagation method stops the move upwards bubbling (on one event only), but all the other handlers still run on the current element.

To halt the bubbling process and avoid the execution of handlers on the current element, one can utilize the event.stopImmediatePropagation method. This method serves to terminate both the bubbling of events and the execution of any additional handlers associated with that event. Consequently, if an element possesses multiple event handlers for a particular event, the invocation of event.stopImmediatePropagation will effectively prevent all of those event handlers from being executed as they bubble up.

Do not use event bubbling unnecessarily.

While event bubbling offers a practical solution, it is advisable not to rely on it exclusively. This caution arises from the fact that the event.stopPropagation method can introduce subtle issues that may lead to complications in the future.

Let's understand it via an example:

  • Create a nested menu where each submenu handles click on its elements, and to stop the triggering of the outer menu, it invokes the event.stopPropagation method.
  • Now for tracking the user's behavior on the click, afterward, we decided to catch clicks on the whole Window for which the document.addEventListener('click') is used.
  • But as we have called the event.stopPropagation method, our analytic would not do anything where clicks get stopped due to stopPropagation , and so we get a dead zone for it.

The notion of event bubbling cannot be fully grasped without an understanding of event capturing. Therefore, let's start with event capturing and subsequently merge both ideas to gain a comprehensive understanding of their functionality and interplay.

Event Capturing

The Netscape Browser was the pioneer in implementing the concept of Event Capturing. This mechanism is the reverse of event bubbling; in Event Capturing, an event travels from the outermost element down to the intended target. Conversely, during event bubbling, the event propagates from the target element back out towards the outermost element in the document. Event Capturing occurs prior to event bubbling; however, it is infrequently utilized since event bubbling typically suffices for managing the event flow efficiently.

Example of Event Capturing

Let’s examine a sample code to gain insight into how Event Capturing operates:

Example

<!DOCTYPE html>

<html>

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width">

  <title>Event Capturing</title>

</head>

<body>

  <div id="p1">

    <button id="c1">I am Child</button>

  </div>

  

  <script>

    var parent = document.querySelector('#p1');

    var child = document.querySelector('#c1');



    parent.addEventListener('click', function(){

      console.log("Parent is invoked");

    },true);

	child.addEventListener('click', function(){

      console.log("Child is invoked");

    });

  </script>

</body>

</html>

Output:

Explanation of Code:

  • The above-described code is based on HTML and JavaScript.
  • In the HTML portion, we have created a div id holding id = p1. Inside the div, we have nested and created a button with id = c1.
  • Moving towards the JS code, initially, we have assigned the html element, i.e., the p1 id, to a variable parent using the querySelector method and the same we have done with the c1 id where we have assigned it to a variable child.
  • Then we have used a click event and attached it to both the p1 div and c1 button. Also containing a function for printing the appropriate message on the console. It means if the child event is invoked first, then it will print the "Child is invoked" message on the console first, and if the parent event handler is invoked first, it will "Parent is invoked" message on the console first.
  • Next, we have added a third argument of addEventListner to true in order to enable event capturing in the parent div.
  • When we click on the button, it first executes the function, which is attached in the parent div.
  • Afterward, the onclick function of the button runs, and it is because of event capturing. Due to event capturing, the event of the parent element executes first, and then the event of the target element gets executed.

Therefore, upon clicking the button, the click event is executed in the sequence illustrated in the flowchart below:

Complete Concept of Event Flow

The diagram presented below illustrates the progression of the event flow:

Consequently, event handling and event capturing serve as the fundamental principles of event delegation. These concepts represent the remarkable capability of event flow.

Input Required

This code uses input(). Please provide values below: