Events in JavaScript are one of the core features of the language that have given us the modern, reactive internet that we know and love today. They allow us to bring HTML elements to "life", so to speak, letting them listen and observe a user's interaction and respond by firing off a piece of code that has a dynamic effect on the page.
A few examples of commonly used event listeners include onclick
, onmouseover
, onchange
, and many others. These all allow a developer to set an HTML element to "listen" for user interactions, and then carry out a function of block of logic that the developer has defined elsewhere (or inline.) Events don't just stop with these more straightforward examples, of course. Many of JavaScript's in-built window manipulations are built on top of complex events, and would take up an entire blog post on their own!
Today, we're mostly interested in one particular feature of events, and how to control it: Event Bubbling.
What is Event Bubbling?
Let's first set up an example to visualize what Event Bubbling is, and what it does. Imagine you've hypothetically created a web page featuring several nested elements, each of which has an onclick
event listener attached to it with a different effect:
<div onclick="alert('I'm a div!')">
<div onclick="alert('I'm a nested div!')">
<h1 onclick="alert('I'm an h1 tag!')">
Hello
</h1>
</div>
</div>
Now, let's say this is rendered to the page, and you decide to click on the h1
tag. What do you think will happen?
First, the alert for the h1
tag will pop up. Then, when you close out of that, the alert for the nested div
will pop up! And last but not least, the outer div
's alert will pop up as well. Why did this happen if you only clicked on the most nested element?
This happens because of Event Bubbling, a feature of JavaScript that causes every action or interaction on a page to "bubble up" through its enclosing elements until it reaches the root of the page, applying that same action to any other event listeners along the way.
Event bubbling happens on almost every event in JavaScript, and is an intentional and desired feature of the language for many reasons. Oftentimes it won't even rise to the attention of a developer or user. However, what if there was a specific occasion where we didn't want an event to bubble up?
Why wouldn't I want events to bubble?
Let's say that you've created an application that features cards displaying relevant information to a user. On each card, you've added an event listener for an onclick
effect that will flip the card over and display more information.
In addition, you've added a button that will delete the card from the page (for whatever reason), prompting the user for a confirmation before doing so, which is a key feature that you don't want to compromise on.
Let's take a look at it in (very) simplified code:
<div class="card" onclick="(Flip-over function)">
<p>(Information)</p>
<button onclick="(Close function)">X</button>
</div>
This would all work fine, except for the fact that if you click the "X" button to close the card, the confirmation would pop up but the card would also flip over. This might not be a huge issue, but it might not make sense to how you've designed the card; maybe you haven't included an "x" button on the back of the card, or you think it just looks a bit sloppy.
This is exactly the kind of situation in which you might want to stop the event bubbling that's causing both onclick
events to fire off sequentially.
How do we stop Event Bubbling?
Thankfully, the answer is quite simple! We use a method of the Event interface called stopPropagation().
Essentially, stopPropagation() does what the name describes: it stops the propagation of a bubbling event from going further up the tree of elements that it's occurring in.
(It's important to note that stopPropagation() doesn't stop the default action of an element from occurring. In order to do that, you would need a separate method called preventDefault().)
Let's apply this to our example code and see how we might stop the onclick
event from propagating. Since we still want the button element to carry out its effect and stop there, we can wrap it in an inline element like span
and use stopPropagation() on that to act as a closed door around it:
<div class="card" onclick="(Flip-over function)">
<p>(Information)</p>
<span onclick="event.stopPropagation()">
<button onclick="(Close function)">X</button>
</span>
</div>
And that's all there is to it! You would now be able to click the button and have its effect fire off without reaching the parent div
, keeping both actions separated.
It's worth noting that the same method can be used in other JavaScript libraries and Frameworks like React. Here's the same example using JSX syntax:
<div className="card" onClick={"(Flip-over function)"}>
<p>(Information)</p>
<span onClick={e => e.stopPropagation()}>
<button onClick={"(Close function)"}>X</button>
</span>
</div>
There's plenty more to learn about Events, Event Bubbling and methods like stopPropagation(), so I encourage you to dive deeper and find more tools to improve your development! This is a relatively simplistic tutorial on a very complex aspect of JavaScript, and there's always more to learn. 😄
Thanks for reading!
Top comments (1)
Thanks for this. Is there a reason why you didn't just put the stopPropagation() in the button tag like this?