logo

Event Propagation Visualizer

Free online event propagation visualizer. Click nested boxes and watch a DOM event travel through the capture, target, and bubble phases, toggle listeners on each layer, and see exactly where stopPropagation cuts the path off.
logo
Paji Dev Workshop
Event Propagation Visualizer

Event Propagation Visualizer

Free online event propagation visualizer. Click nested boxes and watch a DOM event travel through the capture, target, and bubble phases, toggle listeners on each layer, and see exactly where stopPropagation cuts the path off.
Processing

About event propagation

The three phases

When you click an element, the event does not just fire on that element. It starts at the top of the tree and travels down to the target (the capture phase), fires at the target itself (the target phase), and then travels back up to the top (the bubble phase). By default, listeners you add run in the bubble phase, which is why a click on a child also triggers handlers on its ancestors. Adding a listener in capture mode makes it run on the way down instead.

Stopping propagation

Calling stopPropagation inside a listener stops the event from travelling any further, so listeners on the remaining layers never run. It does not stop other listeners on the same element — stopImmediatePropagation does that. Pick a stop point above to see the trigger order get cut short.

FAQ

Common questions and answers about this topic.

What is the difference between capture and bubble?

They are two directions of the same journey. Capture runs top-down, from the outermost ancestor toward the target, before the target is reached. Bubble runs bottom-up, from the target back toward the outermost ancestor. A listener added the normal way runs in the bubble phase; passing true as the third argument to addEventListener runs it in the capture phase instead.

Why does a parent handler run when I click a child?

Because of bubbling. After the event fires on the child (the target), it travels back up through every ancestor, running each one's bubble-phase listener along the way. This is often useful — it lets one handler on a container respond to clicks on any child — but it surprises people who expect the event to stay on the element they clicked.

When should I use stopPropagation?

Use it sparingly, when a child needs to handle an event and genuinely must prevent an ancestor from also reacting — for example a button inside a clickable card that should not trigger the card's click. Reaching for it too often usually means the event design could be simpler; it can also break other code that legitimately relies on the event reaching a shared ancestor.