#todo - rewrite for clarity
The standard DOM Events describes 3 phases of event propagation:
When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors. That's bubbling. Most events bubble, but some do not, like focus.
<form onclick="alert('form')">FORM <div onclick="alert('div')">DIV <p onclick="alert('p')">P</p> </div> </form>
Clicking the div
will call the div
and form
onclick
.
The most deeply nested element that caused the event is called a target element, accessible as event.target
.
event.currentTarget
also exists, but that references the current element that is running the handler. In the above example, the form
event handler will have a currentTarget
of form
, assuming that event.target
= div
.
There's two ways to stop an event bubbling:
event.stopPropagation
- prevents parent element event handlers (think upwards)event.stopImmediatePropagation
- prevents all other event handlers (e.g. other handlers on the same element and event)
You should only stop these if there's a specific need.Most things rely on the bubbling phase, as that's the default for addEventListener
. The capturing phase is rarely used. It's effectively the opposite of the bubbling phase, starting from the root element and ending at the original target.
Technically propagation works in both directions, meaning you can stop something in the capture phase too.
Note that event.preventDefault
is different from the event traversal entirely - it stops the default action of the element, e.g. prevent an a
from navigating.
[[20250527044242-event-delegation]]
https://web.dev/eventing-deepdive/ https://tr.javascript.info/bubbling-and-capturing