DEV Community

Ayako yk
Ayako yk

Posted on

Understanding Events and Event Bubbling in JavaScript

What are Events and Event Handlers?
Events are signals triggered by actions, such as a user clicking a button, pressing keys, or a page finishing loading. To define how the browser should respond to these signals, we use event handlers --- blocks of code that execute when the events occur.

addEventListener()
addEventListener is the recommended method for event handlers.

const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  document.body.style.backgroundColor = "blue";
});
Enter fullscreen mode Exit fullscreen mode

MDN
(This example is from MDN but has been simplified.)

Event Objects
When an event occurs, an event object is created and automatically passed to the event handler. This object provides extra features and information about the event. It is commonly written as e, evt, or event.

event.target

A reference to the object to which the event was originally dispatched.

event.currentTarget

[A reference to] the element to which the event handler has been attached.

Event Bubbling
When we include a delete icon with an SVG, we often surround it with a <button>and add an event handler to it for semantic and accessibility reasons. However, clicking directly on the icon still works perfectly due to the event bubbling.

In this code snippet, the <div>is a parent element, and the <button> is its child element. When we add an event handler (handleClick) to the parent <div> and click the button, the event handler is still triggered because the event bubbles up from the child <button> to the parent <div>.

<div id="container">
  <button>Click me!</button>
</div>

<script>
    const container = document.querySelector("#container");
    function handleClick(e) {
      console.log("Container clicked");
    }

    container.addEventListener("click", handleClick);
</script>
Enter fullscreen mode Exit fullscreen mode

event.target and event.currentTarget

<div id="container">
  <button>Click me!</button>
</div>
<pre id="output1"></pre>
<pre id="output2"></pre>

<script>
    const output1 = document.querySelector("#output1");
    const output2 = document.querySelector("#output2");

    function handleClick(e) {
      output1.textContent += `You clicked on a ${e.target.tagName} 
    element\n`;

      output2.textContent += `You clicked on a 
    ${e.currentTarget.tagName} element\n`;
    }

    const container = document.querySelector("#container");
    container.addEventListener("click", handleClick);
</script>
Enter fullscreen mode Exit fullscreen mode

MDN
(These examples are from MDN but have been modified.)

When an event occurs on an element, it first runs on the element itself and then bubbles up to its parent elements (or ancestors).
What happens if parent elements also have event handlers?

<form onclick="alert('form')">FORM 
    <div onclick="alert('div')">DIV 
        <p onclick="alert('p')">P</p> 
    </div> 
</form>
Enter fullscreen mode Exit fullscreen mode

If we click on the innermost child "P", the alerts will be shown in the order of p, div, and form. The event propagates upward through the DOM hierarchy, triggering event handlers attached to each ancestor.

The Modern JavaScript tutorial

Stop Propagation
Event bubbling is useful, as discussed above, but it can sometimes cause unintended behavior. To prevent this, we can use the stopPropagation() method.

<form>FORM 
    <div>DIV 
        <p>P</p> 
    </div> 
</form>

<script>
    const form = document.querySelector("form");
    const div = document.querySelector("div");
    const p = document.querySelector("p");

    form.addEventListener("click", () => alert("form"));
    div.addEventListener("click", () => alert("div"));
    p.addEventListener("click", (event) => {
        event.stopPropagation();
        alert("p");
       }
    );
</script>
Enter fullscreen mode Exit fullscreen mode

Now, clicking on "P" only triggers the alert 'p', and no alerts from its parent elements are shown.

Event bubbling can be incredibly useful when used properly. It becomes more powerful when combined with event delegation and the event.target property. I'll explore these concepts in my next blog.

Top comments (0)