What is event bubbling in JavaScript?

What is event bubbling in JavaScript?

User interactions are now an essential component of every web application. We may use several user events to improve and engage the user experience. Using JavaScript, we can easily handle user events on a DOM element. We may believe that an event applied to a particular DOM element operates exclusively for that specific DOM element. It is entirely false (except for a few events). Event bubbling is an essential phenomenon we frequently overlook while dealing with events.

This article will discuss the event bubbling and why we utilize it. In addition, we will learn about numerous methods to use event bubbling to increase application performance. Finally, we’ll review techniques for avoiding event bubbling while handling events.

What is event propagation?

Simply said, event propagation is the propagation of events. Event propagation is the propagation of an event from a child element to the parent elements and vice versa. An event that occurs on a child element in the DOM tree will also propagate to its parent elements and vice versa.

In the DOM tree, an event may propagate from top to bottom or bottom to top. Event bubbling occurs when an event propagates from the bottom to the top of a hierarchy. Otherwise, event capture occurs when events flow from bottom to top in the hierarchy.

Event bubbling and capturing.
Event bubbling and capturing.

Order of propagation

Event propagation occurs in two phases:

  1. Capturing phase: Event capturing occurs at this phase. The event propagates from the top to the target element, which is the element where the event happened.
  2. Target phase: The event propagation reaches the target element during this phase.
  3. Bubbling phase: Event bubbling occurs at this phase. The event propagates from the target element, which is the element where the event happened, to the top.

What is event bubbling?

Event bubbling is the propagation of events from the bottom to the top of the DOM tree, from child elements to parent elements. It is one sort of event propagation. Another form is event capturing, which occurs when events propagate down the DOM tree from parent to child elements.

Let’s look at an example to understand event bubbling better. Consider three nested div components with the IDs ‘grandparent,’ ‘parent,’ and ‘child.’

<div id="grandparent">
    <div id="parent">
        <div id="child"></div>
    </div>
</div>Code language: HTML, XML (xml)
Nested div elements.
Nested div elements.

Using JavaScript, we’ve added a ‘click’ event listener to each div component. When the user clicks on the div element, the event is triggered. When the event listeners are activated, the callback supplied to them logs some string.

grandparent.addEventListener('click', function (event) {
    console.log('Grandparent clicked!');
});

parent.addEventListener('click', function (event) {
    console.log('Parent clicked!');
});

child.addEventListener('click', function (event) {
    console.log('Child clicked!');
});Code language: JavaScript (javascript)

Let us examine the logs in the browser console by clicking on the child div element.

Console output on clicking the child div element.
Console output on clicking the child div element.

Even though we have clicked on the child div element, the event listeners of the parent and grandparent div elements are also triggered. Also, the order of event firing is from the child element to the grandparent element, i.e., from bottom to top in the hierarchy. It is all due to event bubbling.

Except for a few exceptions, almost all events bubble up the DOM tree. For example, the following events are not subject to event bubbling: ‘blur,’ ‘focus,’ ‘load,’ etc.

Stopping event propagation

Event propagation can sometimes be beneficial, although we rarely need it daily. Depending on our approach, it may occasionally produce bugs and may be irritating. In JavaScript, we may stop event propagation quickly.

event.stopPropagation()

We can quickly halt event propagation by calling event.stopPropagation(). The event is stopped instantly on the element to which we have applied the event.stopPropagation() function in the event listener.

parent.addEventListener('click', function (event) {
    event.stopPropagation();
    console.log('Parent clicked!');
});Code language: JavaScript (javascript)

When we click the child div element, the event propagates upwards but is halted at the parent div element and does not reach the grandparent div element.

Event propagation halted at the parent div element.
Event propagation halted at the parent div element.

event.stopImmediatePropagation()

It is similar to the event.stopPropagation() method. Instead of stopping a single event from flowing beyond the element, it prevents all events from propagating.

parent.addEventListener('click', function (event) {
    event.stopImmediatePropagation();
    console.log('Parent clicked!');
});
Code language: JavaScript (javascript)

When we click the child div element, the event propagates upwards but is halted at the parent div element and does not reach the grandparent div element.

Event propagation halted at the parent div element.
Event propagation halted at the parent div element.

Try event.stopImmediatePropagation() in place of event.stopPropagation() if event.stopPropagation() doesn’t work in some circumstances.

event.target vs event.currentTarget

It can be difficult to decide whether to use event.target or event.currentTarget. Both of these return a DOM element that is related to the event. The distinction between the two is that event.target returns the element where the event happened, whereas event.currentTarget returns the element where the propagated event has arrived.

Let’s make a few changes to the JavaScript we created before. Inside the event listener, now print the target and current target ID.

grandparent.addEventListener('click', function (event) {
    const targetID = event.target.id;
    const currentTargetID = event.currentTarget.id;
    console.log('Grandparent clicked!', `Target: ${targetID}, Current Target: ${currentTargetID}`);
});

parent.addEventListener('click', function (event) {
    const targetID = event.target.id;
    const currentTargetID = event.currentTarget.id;
    console.log('Parent clicked!', `Target: ${targetID}, Current Target: ${currentTargetID}`);
});

child.addEventListener('click', function (event) {
    const targetID = event.target.id;
    const currentTargetID = event.currentTarget.id;
    console.log('Child clicked!', `Target: ${targetID}, Current Target: ${currentTargetID}`);
});Code language: JavaScript (javascript)

When users click on the child div element, the event will propagate upward, triggering the event listeners of the child, parent, and grandparent div elements. When the event listeners run the callback, we log the target and the current target ID.

Target v/s current target.
Target v/s current target.

The child div element is the target element in all three events since it was the one that originated the event, which then propagated upward. The current target is the div element from which the event listeners got triggered, i.e., the elements to whom the event has propagated.

If we do not use event bubbling and only want the element linked with the event, we may use either.

Use cases for event bubbling

When we need to add an event listener to each element in a list of items, event bubbling might be handy. The number of event listeners will grow in proportion to the size of the list. It comes with the possibility of decreasing performance. In addition, each time we add a new item to the list, we would need to construct a listener.

Take, for example, a to-do list. We need to add a delete functionality to the list so that when a user clicks on a list item, it gets deleted. One method is to attach an event listener to each list item. We have discussed the disadvantages of this technique previously. A clever way to accomplish this is to attach an event listener to the parent and handle any events that occur on the list items on the parent.

<ul id="list">
    <li>Eat apple</li>
    <li>Code</li>
    <li>Work out</li>
    <li>Read a book</li>
</ul>Code language: HTML, XML (xml)
const list = document.getElementById('list');

list.addEventListener('click', function (event ) {
    event.target.remove();
});Code language: JavaScript (javascript)

The event.target object provides us with the target element on which the event happened. When users click a list item, the event gets bubbled up to the parent. We can quickly delete the list item the user clicked from the DOM because we know the item the user clicked using event.target.

Deleting an item from the list.
Deleting an item from the list.

It was a primary use case, but we may utilize it for more complicated use cases to enhance efficiency and reduce code size significantly.

Conclusion

In this article, we covered event bubbling and why we used it. In addition, we learned about several strategies for using event bubbling to improve application speed. Finally, we looked at several ways to prevent event bubbling while processing events.

You can access all the source code here

Thank you so much for reading ?

Sharing is caring

Did you like what Varun Tiwari wrote? Thank them for their work by sharing it on social media.

0/10000

No comments so far