Stopping event bubbling in JavaScript

Event bubbling can be stopped on any element through which the event is bubbling. To do this, call the stopPropagation method of the Event object in the element code.

In the following example, clicking on the red block will work on itself, then on the blue block and that's it - the blue block stops further bubbling and the green block will not react in any way:

elem1.addEventListener('click', function() { console.log('green'); }); elem2.addEventListener('click', function(event) { console.log('blue'); event.stopPropagation(); // stops the propagation }); elem3.addEventListener('click', function() { console.log('red'); });

You can check:

Multiple handlers on an element

If an element has several handlers for one event, then even if the bubbling stops, all of them will be executed. That is, stopPropagation prevents the event from progressing further, but all handlers will work on the current element. See example:

elem1.addEventListener('click', function() { console.log('green'); }); elem2.addEventListener('click', function(event) { console.log('blue - the first handler'); event.stopPropagation(); // stops the bubbling }); elem2.addEventListener('click', function() { console.log('blue - the second handler'); // still works }); elem3.addEventListener('click', function() { console.log('red'); });

You can check:

Immediate termination of bubbling

To completely stop processing, modern browsers support the stopImmediatePropagation method. It not only prevents bubbling, but also stops event processing on the current element. Let's apply it:

elem1.addEventListener('click', function() { console.log('green'); }); elem2.addEventListener('click', function(event) { console.log('blue - the first handler'); event.stopImmediatePropagation(); // stops the bubbling }); elem2.addEventListener('click', function() { console.log('blue - the second handler'); // won't work anymore }); elem3.addEventListener('click', function() { console.log('red'); });

You can check:

Practical usage

Let inside one parent we have a button and some block:

<div id="parent"> <button>click me</button> <div id="block"> text </div> </div>

Get references to our elements into variables:

let parent = document.querySelector('#parent'); let button = document.querySelector('button'); let block = document.querySelector('#block');

Let our block be initially hidden:

#block:not(.active) { display: none; }

Let's make it so that by clicking on the button our block appears:

button.addEventListener('click', function() { block.classList.add('active'); });

And now we will make it so that by clicking on any place of the parent, our block is hidden:

parent.addEventListener('click', function() { block.classList.remove('active'); });

However, we are in for an unexpected surprise: since the button is inside the parent, then clicking on the button simultaneously means also clicking on the parent. This means that at first our block will appear, and then, due to the bubbling of the event, the handler in the parent will work and our block will be hidden.

This is where the ability to cancel the bubbling comes in handy: we can make it so that when you click on the button to cancel the bubbling, the parent does not react to this click.

Implement the correct performance of the described task on your own.

enru