Computer scienceProgramming languagesJavaScriptInteraction with a browserDOM Events

Bubbling and capturing events

11 minutes read

The most frequently used terms in JavaScript while an event flow is occurring are event bubbling and event capturing. Bubbling and Capturing are the two ways of event propagation in the HTML DOM API and are widely used for the development of web applications using JavaScript. In this topic, you will learn how you can use event bubbling and capturing while developing a webpage or a web application.

The event flow

Before getting to the bubbling and capturing, you need to understand the propagation of an event inside the document object model, or DOM. But first, let's learn about the events.

In JavaScript, events are occurrences that have the potential to start certain processes that result in a specific behavior. A "click" or a "hover" are frequent examples of an event. You can configure event listeners to keep an eye out for certain events that will launch the functionality you want.

Next, let's study propagation. We often get confused as to which event handler will fire first if there are multiple nested elements handling the same event. Hence, it becomes important to first understand the sequence of events. An event typically propagates from its parent element to the target element first, and then it propagates back to its parent element. So, all in all, there are three phases in a JavaScript event that are listed below:

  • Capture Phase. The propagation begins from the window object or the root element. Event propagation starts from the ancestors and moves towards the parent's target element.
  • Target Phase. The event reaches the target element.
  • Bubble Phase. It is the reverse of the Capture phase, the event is propagated from the target to the ancestors (window object).

The event propagation is summarized in the image below:

The event propagation

Event bubbling

The idea of event bubbling is utilized while creating a webpage or website using JavaScript, where the event handlers are called when two elements are nested on top of each other and are involved in the same event. Event bubbling is therefore used when performing event flow for a web page or a web application. When two components are nested inside one another and both elements have registered listeners for the same event, event bubbling can be understood as a series of calls to the event handlers. Hence, calling is carried out starting with the base element and moving upward via all of its ancestors.

Let's take an example to better understand bubbling.

<body>
  <div class="first-div" id="grandparent">
    First div
    <div class="second-div" id="parent">
      Second div
      <button class="button" id="child">Button</button>
    </div>
  </div>
  <script>

    const grandParent = document.getElementById("grandparent");
    const parent = document.getElementById("parent");
    const child = document.getElementById("child");

     grandParent.addEventListener(
      "click",
      (event) => {
        console.log("Reached GrandParent");
      },
      { capture: false }
    );

    parent.addEventListener(
      "click",
      (event) => {
        console.log("Reached Parent");
      },
      { capture: false }
    );

    child.addEventListener(
      "click",
      (event) => {
        console.log("Reached Child");
      },
      { capture: false }
    );

    document.addEventListener("click", (event) => {
      console.log("Document");
    }),
      { capture: false };
  </script>
</body>

Here, the third parameter of the event listener is a capture. The capture can accept boolean values, i.e. true or false. It is used to tell whether an event is in the bubbling or capturing phases. If capture is not specified, then it is automatically set to false, so only Event bubbling will occur all over to the parent element.

Here is the output of the example from above:

The output of the example

In the above example, the button is clicked. It acts as a child of the second-div and the first-div acts as a grandparent of the child i.e. button. As we click on the button, the event listener detects a click event, so we should get "Reached Child" in the console. But it is not the case here because we got a different result in the console. The first-div, second-div and the document itself are not clicked but the event listeners of the same are responding and printing in the console because of the event bubbling.

Here comes the concept of event propagation and hence bubbling events. When we click on the button, the event is propagated from the child element all the way to the parent element, here document. So, when the button is clicked, the event propagation is moving from the button i.e. child element to the parent element in the DOM i.e. document. Therefore, the events are bubbling up and reach to the parent element.

Event capturing

The outside event handler fires in event capturing before the specified handler. For instance, let's consider a button inside the div container. Here, the div's event i.e. parent's event occurs before the button's event:

Let's take an example to understand event capturing:

<body>
  <div class="first-div" id="grandparent">
    First div
    <div class="second-div" id="parent">
      Second div
      <button class="button" id="child">Button</button>
    </div>
  </div>
  <script>
    const grandParent = document.getElementById("grandparent");
    const parent = document.getElementById("parent");
    const child = document.getElementById("child");

     grandParent.addEventListener(
      "click",
      (event) => {
        console.log("Reached GrandParent");
      },
      { capture: true }
    );

    parent.addEventListener(
      "click",
      (event) => {
        console.log("Reached Parent");
      },
      { capture: true }
    );

    child.addEventListener(
      "click",
      (event) => {
        console.log("Reached Child");
      },
      { capture: true }
    );

     document.addEventListener(
      "click",
      (event) => {
        console.log("Document");
      },
      { capture: true }
    );
  </script>
</body>

Here is the output of the above code snippet:

The output of the above code snippet

In the above example, when the button is clicked, the parent div of the HTML document is printed at first and it reaches all the way down to the element from which the event is generated, here the child element i.e. button. Therefore, you can see the above message in the console.

Stop propagation

Sometimes you may also want to prevent an event from propagating either up or down, in other words, bubbling or capturing in the DOM tree. You can achieve this by using the stopPropagation method on the event object.

Let's see how you can do this with an example:

Note that the same HTML and CSS files from above are used in the code snippet below.
<script>
  const grandParent = document.getElementById("grandparent");
  const parent = document.getElementById("parent");
  const child = document.getElementById("child");

  grandParent.addEventListener("click", (event) => {
    console.log("Reached GrandParent");
  });

  parent.addEventListener("click", (event) => {
    console.log("Reached Parent");
    event.stopPropagation();
  });

  child.addEventListener("click", (event) => {
    console.log("Reached Child");
  });

  document.addEventListener("click", (event) => {
    console.log("Document");
  });
</script>

In the code snippet above, we've added a call to the stopPropagation method in the event handler for the parent div element. This method prevents the event from bubbling up to the outer elements, grandParent, and document as you can see in the output below. Therefore when you click the button, the bubbling event occurs until event.stopPropagation() comes into the picture. So, only "Reached Child" and "Reached Parent" will be logged into the console.

"Reached Child" and "Reached Parent"  logged into the console

Conclusion

Now you should know more about event propagation in JavaScript. There are three phases of event propagation: Capture Phase, Target Phase, and Bubble Phase. The bubbling and capturing events in JavaScript can be used effectively to handle the events in web applications. Also, you now should have control over the unexpected event bubbling or capturing if you know how to perfectly use it inside any web application.

22 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo