Event bubbling is an incredibly useful feature of JavaScript. But there might come a time when you need to prevent it. You can do that using the stopPropagation() and stopImmediatePropagation() methods.

The stopPropagation() method

There are three distinct phases an event goes through. I outlined these in my post about event flow:

  1. Capture
  2. Target
  3. Bubble

The MDN Web Docs explain that the stopPropagation() method prevents further propagation of the current event in the capturing and bubbling phases.

Imagine the following HTML. We have a button element inside a div element:

<div>
<button type="button">Click Me!</button>
</div>

Now imagine the following JavaScript. We select the div element and add an event listener to it. This shows an alert dialog that says "I'm a div" whenever the div or any of its children is clicked:

var div = document.querySelector("div");

div.addEventListener("click", function () {
alert("I'm a div!");
});

Although we attached the event listener to the div, it will still run when the button is clicked.

This is because, when clicked, the button is the element that actually fires the event (the event.target).

Now, let's add a separate event listener to the button element. Inside it, we'll call the stopPropagation() method:

var div = document.querySelector("div");
var button = div.querySelector("button");

// This WILL NOT run when the button is clicked
div.addEventListener("click", function () {
alert("I'm a div!");
});

button.addEventListener("click", function (event) {
event.stopPropagation();
});

With this in place, the alert dialog will not show when the button is clicked.

This is because the stopPropagation() method stops the event from reaching the div element.

The stopImmediatePropagation() method

This is all well and good, but what if we had an additional click handler on the button element?

Imagine the following JavaScript. It's the same as before, except I've added another event listener to the button. It shows an alert dialog when the button is clicked:

var div = document.querySelector("div");
var button = div.querySelector("button");

// This WILL NOT run when the button is clicked
div.addEventListener("click", function () {
alert("I'm a div!");
});

button.addEventListener("click", function (event) {
event.stopPropagation();
});

// This WILL run when the button is clicked
button.addEventListener("click", function () {
alert("I'm a button!");
});

With this code, the "I'm a div" alert will not show when the button is clicked. This is the same as before.

However, the new "I'm a button" alert will show.

What if we wanted to prevent this? We're in luck, because we can use the stopImmediatePropagation() method.

The MDN Web Docs explain:

If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. If stopImmediatePropagation() is invoked during one such call, no remaining listeners will be called.

In other words, the stopImmediatePropagation() method prevents other listeners of the same event from being called.

Let's change the button element's first event listener so that it calls the stopImmediatePropagation() method instead:

var div = document.querySelector("div");
var button = div.querySelector("button");

// This WILL NOT run when the button is clicked
div.addEventListener("click", function () {
alert("I'm a div!");
});

button.addEventListener("click", function (event) {
event.stopImmediatePropagation();
});

// This WILL NOT run when the button is clicked
button.addEventListener("click", function () {
alert("I'm a button!");
});

Now, when the button is clicked, the "I'm a button" alert from the new event listener will not show.

This is because the stopImmediatePropagation() method prevents other listeners of the same event from being called.

Avoid these methods if possible

Event bubbling is a helpful and powerful feature of JavaScript. You shouldn't prevent it unless you really need to.

The Bubbling and capturing lesson from JavaScript.info explains:

Bubbling is convenient. Don’t stop it without a real need: obvious and architecturally well thought out.

Sometimes event.stopPropagation() creates hidden pitfalls that later may become problems.

For a detailed example, check out the lesson on JavaScript.info.

Summary

You can use the stopPropagation() method to stop an event from propagating further up the DOM.

The stopImmediatePropagation() method does this too, but it also stops other listeners of the same event* from being called.

I've made a quick demo on CodePen to show the difference.