The DOM has two ways for objects to detect events: from the top down, and from the bottom up. The first method is known as event capturing, the second is called event bubbling. With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements. With capturing, the event is first captured by the outermost element and propagated down to the inner elements.
The standard DOM Events describes 3 different phases of event propagation:
- Capturing phase: the event goes down to the element.
- Target phase: the event reached the target element.
- Bubbling phase: the event bubbles up from the element.
The event bubbling process starts by executing the event handler defined for individual elements at the lowest level of the DOM, i.e, where the event originated. From there, the event bubbles up to the containing elements (e.g. a table or a form with its own event handler), then up to even higher-level elements (e.g. the
BODY element of the page).
Several listeners can be registered on a node for the same event type. When the propagation reaches one such node, listeners are invoked in the order of their registration. Also, the branch determination is static, that is, it is established at the initial dispatch of the event. Tree modifications occurring during event processing will be ignored.
Finally, the event ends up being handled at the highest level in the DOM hierarchy, the
document element itself (provided that your
document has its own event handler) and from there, up to the outermost object: the
window object. Note that while the
window object is not actually a DOM node but since it implements the
EventTarget interface, we are handling it like it was the parent node of the document object.
Event capturing is the opposite of bubbling (events are handled at higher levels first, then sink down to individual elements at lower levels). Event capturing is supported in fewer browsers and rarely used; notably, Internet Explorer prior to version 9.0 does not support event capturing.
Event bubbling and capturing example
In the example below, if you click on any of the highlighted elements, you can see that the capturing phase of the event propagation flow occurs first, followed by the bubbling phase.
Stopping event bubbling
In some situations, you only want the event to trigger handlers on the element itself, without bothering all its ancestors. In these cases, you can call the stopPropagation() method while executing the event handler and this will prevent all of its ancestors’ event handlers from being triggered. Note that you can also stop the bubbling later on if you’d like, it doesn’t have to be on the event target itself.
If an element has multiple event handlers on a single event, then even if one of them stops the bubbling, the other ones still execute. In other words,
event.stopPropagation() stops bubbling upwards, but not on the current element. All other handlers for that node will still run. If you wan to both stop the bubbling and prevent handlers on the current element from running, you must call the
event.stopImmediatePropagation() method. After calling this method no other handlers will execute.
Stopping event propagation is not a recommended coding choice. Bubbling is convenient. Don’t stop it without a real need: obvious and architecturally well-thought. There’s usually no real need to prevent the bubbling and sometimes doing it creates hidden pitfalls that may become problems later. A task that seemingly requires stopping event bubbling can almost always be solved by other means.