📌 JavaScript

Event bubbling in JavaScript all you need to know about

January 06, 2022

The interactivity on webpages in the browser happens with the help of JavaScript. Javascript calls every action that happens on the webpage as an event. There's a way how events get propagated in different directions in the DOM(Document Object Model) tree.

Event bubbling in Javascript refers to the way how events get propagated from the innermost element to the outermost element of the DOM often the document.

Event bubbling in JavaScript

When an event happens on an element, the event handler attached to that element runs first, then parent's handler and followed by all other ancestors' handlers. This is what bubbling in JavaScript is.

Let's understand it better with the help of a simple example.

<article onclick="alert('article')">
  <section onclick="alert('section')">
    <div onclick="alert('div')">Text to click</div>

When you run the above code snippet in the browser and click on the text, you can see an alert box with div message, followed by another alert with section message and it is followed by another alert with article message. 

And that shows clearly that our event of clicking is propagating up and triggering other event handlers on the parent and ancestor elements of div. And this even propagation won't stop until the article element, it keeps going and going until it reaches html element and then to the document object.

Event bubbling is the default behaviour in JavaScript and it has various use cases, like sometimes analytic tools want to capture user moments, clicks etc and all such things happen because of event bubbling. 

Similar to bubbling there's another concept called event capturing and this works opposite to bubbling.

In bubbling events propagate from the innermost element to the outermost parent and in capturing events propagate from the outermost parent to the innermost element.

Stop event bubbling in Javascript

It's very simple to stop event bubbling on an element that is to stop triggering the handlers of its parent and ancestor elements.

Let's see the same example to stop this bubbling.

<article onclick="alert('article')">
  <section onclick="alert('section')">
    <div onclick="event.stopPropagation()">Text to click</div>
    <p>Paragraph text</p>

In the above code snippet we have added event.stopPropagation() on the div handler and a new paragraph of text. 

When you click on the div text, nothing happens because we are preventing the event from bubbling, but when you click the paragraph text it bubbles up and triggers the section and article elements' handlers. 

And that's so simple to prevent even bubbling. But in most cases, you don't need to prevent this bubbling of events, and only under specific scenarios you need this stopPropagation method for stopping the bubbling.

<div onclick="event.stopPropagation()">Text to click</div>

The way we have handled the event on div element is the old style of running event handlers and it's not an effective way to handle events like this. 

Preferred way to handle events

The preferred way to handle events on any elements is by using addEventListener method on it.

document.addEventListener(event, function, useCapture);
  • event - type of the event to listen e.g., click, mouseover etc
  • function - function to run after the event occurs
  • useCapture - boolen(default false), if true event propagation happens from parent to the innert most element(child)

So let's see this by considering an example

Event bubbling and capturing with addEventListener

// Event bubbling
  <div>Text to click</div>

const section = document.querySelector('section');
const div = document.querySelector('div');

div.addEventListener('click', (e) => alert('From div'));
section.addEventListener('click', (e) => alert('From section'));

In this event bubbling happens when you click the div text, the event gets propagated to the section handlers and triggers it.

To reverse the event bubbling to go from parent to child, you can just enable the useCapture flag on the parent element.

// Passing third argument with true, 
// enables the section handler to trigger first before div
section.addEventListener('click', () => alert('From section'), true);

Stop event propagation with addEventListener

To stop the event propagation just call the stopPropagation method on the event object of the element you want.

const section = document.querySelector('section');
const div = document.querySelector('div');

div.addEventListener('click', (e) => {
  e.stopPropagation(); // stops propagation to its parent element
  alert('From div');

section.addEventListener('click', () => alert('From section'));

This time when you click the div text, only the div handler runs and there won't be any alert message from section handler.

There's one more method for stopping the propagation of events, it is called stopImmediatePropagation method. This prevents running other handlers when there are multiple event handlers on the same element. 

And this is all about event bubbling in Javascript. Event listeners and event handlers are a very broad topic in Javascript and there are so many things that can be discussed related to the events in JS.

If you like receiving regular tips, tricks related to web development and technology then do follow on devapt-twitter @dev_apt