DEV Community

Cover image for How Event Propagation and Delegation Work in JavaScript
Okure U. Edet Kingsley🧑‍💻🚀
Okure U. Edet Kingsley🧑‍💻🚀

Posted on

How Event Propagation and Delegation Work in JavaScript

Table of Contents

  • Introduction
  • What are events?
  • Event propagation
  • The capturing phase of event propagation
  • The bubbling phase of event propagation
  • Event .stopPropagation method
  • Event delegation
  • How to use event delegation in JavaScript
  • Conclusion

Prerequisite

For the reader to understand this article, it is important to have at least a basic knowledge of HTML, CSS and JavaScript.

Introduction

In JavaScript, events travel to and fro the Document Object Model(Dom) tree. This is generally known as event propagation, which comes in two phases: capturing and bubbling. The fact that events pass through the parent element of the target element that triggered such events can then help you to decide where to handle these events. This is known as event delegation. In this article, you will learn how event propagation and delegation work in JavaScript and how to effectively use them to handle events on your page.

What are events?

JavaScript events are actions or occurrences that trigger certain behavior on a page. Developers can then listen for these events in JavaScript by attaching a function known as Event Listeners. Examples of events in JavaScript include; a click event, where a user clicks on an element in a web page; a submit event, in cases where a user submits a form, page loading; a keyboard event, where the user chooses a key on the keyboard. For more about events, see this https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events

Event propagation

Event propagation in JavaScript refers to how events travel the Document Object Model(DOM) tree. This behavior can be likened to an electric current traveling through the DOM tree once an event is triggered. Event propagation has two phases; capturing and bubbling.

The capturing phase of event propagation

When an event is triggered or fired, the window object gets notified of the event first and then followed by the document element as well as the subsequent parent elements of the target element. This process is known as event capturing.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link type="text/css" href="style.css" rel="stylesheet" />
    <title>TODO LIST</title>
  </head>
  <body class="bg-blue-200">
    <div class="ul">
      <ul class="list">
        <li>Read a book</li>
        <li>Finish writing my article</li>
      </ul>
    </div>
    <script src="script.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
document.querySelector("li").addEventListener("click", function () {
  alert("My todo list!");
});
Enter fullscreen mode Exit fullscreen mode

In the example above, the ul element is a parent element of the li element. The div element is also a parent element of the ul element. It continues like this to the top of the DOM tree and to the window object itself. When an event such as a click event is triggered on the li element, The window object is first alerted or notified of the event. Then it travels downward through each of the parent elements of the target element till it reaches the target element. After the target element has been notified of the event, then begins the second phase of event propagation, also known as event bubbling.

The bubbling phase of event propagation

Once the target element has been notified of the event, the event once again travels up to the root of the DOM tree. Just like in the capturing phase, the event passes through all of its parent elements. This process is known as event bubbling. So as an event ‘bubbles’ through its parent elements, it is as if the event was triggered in that very element. In the code above, once the li element has been alerted of the event, the event then travels upward through the ul element, the div element, passing through the parent elements back to the root of the DOM. Generally, events are always handled either at the target or bubbling phase. However, event listeners can be set up in a way that they listen to events in the capturing phase instead. It is important to note that not all events have a capturing and bubbling phase. Some events, like the focus event, are generated right at the target element and can only be handled there.

Event .stopPropagation() method

Throughout this article, you have seen how event capturing and bubbling work. However, there are times in your code when you may not want an event to bubble. In such cases, you can use the e.stopPropagation() method. This method prevents an event triggered in the target element from bubbling up the DOM tree.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>TODO LIST</title>
    <style>
      body {
        background-color: violet;
      }
      .ul {
        border: 2px solid blue;
        border-radius: 5px;
        margin: auto;
        width: 50%;
        padding: 10px;
        margin-top: 70px;
      }
      ul {
        background: rgb(214, 230, 222);
        padding: 20px;
      }
      ul li {
        background: rgb(217, 230, 212);
        color: black;
        margin: 5px;
      }

      .list {
        background: rgb(21, 75, 75);
      }
    </style>
  </head>
  <body class="bg-blue-200">
    <div class="ul">
      <ul class="list">
        <li>Read a book</li>
        <li>Finish writing my article</li>
      </ul>
    </div>

    <script>
      // Target element
      document.querySelector("li").addEventListener("click", function () {
        alert("My todo list!");
      });

      // Parent element
      document.querySelector("ul").addEventListener("click", function () {
        this.style.background = "red";
      });
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The result of the above code
In the above code, an addEventListener() function is attached to the li element and its parent element ul. When the li element is clicked, the function attached to it executes before its parent function by event bubbling.

The function attached to the  raw `li` endraw  element is executed first

The function attached to the  raw `ul` endraw  element is executed after
We can prevent this from happening by adding an e.stopPropagation() method. This will then prevent the event from propagating when the target element is clicked.

// Target element
      document.querySelector("li").addEventListener("click", function (e) {
        e.stopPropagation();
        alert("My todo list!");
      });
Enter fullscreen mode Exit fullscreen mode

Event delegation

Event delegation is essentially the use of the knowledge that events bubble to instead handle events at any of the parent elements of the target element where the event was triggered. Events are said to be ‘delegated’ to a parent element of the target element so they can be handled right at that element.

How to use event delegation in JavaScript

When you want to use event delegation in your code, there are two things you need to do. Firstly, you add the event listener function to the parent element. After that is done, the next step is to figure out which element triggered the event. Event delegation has many benefits, one of which is to help improve the performance of your code.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>TODO LIST</title>
    <style>
      body {
        background-color: violet;
      }
      .ul {
        border: 2px solid blue;
        border-radius: 5px;
        margin: auto;
        width: 50%;
        padding: 10px;
        margin-top: 70px;
      }
      ul {
        background: rgb(214, 230, 222);
        padding: 20px;
      }
      ul li {
        background: rgb(217, 230, 212);
        color: black;
        margin: 5px;
      }

      .list {
        background: rgb(21, 75, 75);
      }
    </style>
  </head>
  <body class="bg-blue-200">
    <div class="ul">
      <ul class="list">
        <li class="l1 li">Read a book</li>
        <li class="l2 li">Finish writing my article</li>
        <li class="l3 li">Draft my resume</li>
      </ul>
    </div>

    <script>
      // Parent element
      document.querySelector("ul").addEventListener("click", function (e) {
        const target = e.target;
        if (target.classList.contains("li")) {
          target.style.background = "red";
        }
      });
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

In the code above, you will notice that an addEventListener() function has been added to the parent class of the li element. The target property of the event object has been accessed and stored into a target variable. This is then used to check if the target element contains a class of li. If that is true, the code in the if block executes anytime a target element is clicked.

This image displays a list turning red once it is clicked.

Conclusion

In summary, this article has tried to shed more light on event propagation and delegation in JavaScript as well as how they work. While event propagation, with its two phases: capturing and bubbling, describe how events travel up and down the Document Object Model(DOM) tree when they are fired on the target element, event delegation is how you can use the knowledge that events travel through the DOM tree to handle events at any of the parent elements of the target element concerned. Moreover, you can decide to stop the propagation of events by using the e.stopPropagation() method.

Top comments (0)