Events: bubbling i capturing
JavascriptWhen an event occurs on a page, the interpreter does not execute it immediately on the element where it happened (the target element). Instead, it travels to the root element through the DOM model, triggering all identical events along the way. This process is how browsers handle events. This journey is called event propagation.
Event propagation consists of two phases:
- Capturing phase – The interpreter starts traveling from the root element to the element where the event occurred.
- Bubbling phase – The interpreter travels from the element where the event occurred back to the root element.
Browsers use one of these two phases to execute the event. Initially, Netscape introduced the capturing phase for execution, while IE and Firefox implemented bubbling. Today, modern browsers can use either phase to handle events. The default phase is bubbling. If no specific phase is defined, the event will execute starting from the target element where the event occurred and travel upward through the DOM (via parent elements). If we use the method addEventListener()
, we can choose the phase by specifying a third argument. The default value is false
for bubbling, and true
for capturing. In practice, bubbling is far more commonly used than capturing.
TIP: The only way to use the capturing phase in modern browsers is through the addEventListener()
method, where you specify true
as the third argument.
IMPORTANT: It is crucial to remember that both bubbling and capturing phases activate all event handlers (for the same event) on the elements they pass through during their journey through the DOM. For example, if a click event occurs, the interpreter will activate all click event handlers on the elements it traverses. Therefore, it is important to thoroughly understand bubbling and capturing phases, as they can cause significant issues in your code, but they can also be very beneficial if used correctly. (See below: how to stop bubbling and capturing in situations where they are unnecessary and the concept of Event Delegation to leverage bubbling.)
The event object has a property called eventPhase
, which returns a number indicating the current phase of the event: none (0), capture (1), target (2), or bubbling (3).
The deepest element that triggers the first event is called the target element. To access this element, use the property event.target
, or for older versions of IE: var target = event.target || event.srcElement
.
During bubbling or capturing, all elements involved will have the same event.target
value—the originally triggered element.
After the target element, when the next parent event is activated:
event.target/srcElement
– remains unchanged and still refers to the original element that triggered the first event.
this
– refers to the current/most recent element where the event is executed, not the original element (this element must have an event handler).
TIP: Not all events bubble. The blur
, focus
, load
, and unload
events do not bubble like other events.
How to stop bubbling and capturing?
As mentioned, when an event occurs, it travels from the root document to the target element (capturing) and then back to the root (bubbling), activating all existing listeners for the same event along the way. Fortunately, there are methods to stop this propagation.
You can stop bubbling and capturing using the following methods:
1) event.stopPropagation()
– Stops bubbling and capturing on parent or child elements.
2) event.stopImmediatePropagation()
– Stops bubbling and capturing on parent or child elements and prevents additional event handlers (for the same event) from executing on the target element.
event.stopPropagation()
- (For IE9: event.cancelBubble=true;
) – Stops event propagation on parent/child elements of the activated element. To use this method, simply add it to the event handler as follows:
myChildElement.onclick = function(e) { e.stopPropagation(); // Stops bubbling console.log('Propagation stopped! No bubbles!'); // Code executes normally after the event };
IMPORTANT: If there are additional event listeners for the same event on the target element, this method will not stop their execution, only propagation to parent and child elements. To stop further execution of event handlers on the target element as well as bubbling and capturing, use stopImmediatePropagation()
.
If the document structure is highly complex, you can improve performance by disabling propagation. Even if no event listeners exist among parent elements, DOM traversal will still occur.
Many experts today recommend avoiding stopping propagation unless absolutely necessary, as many developers tend to overuse the stopPropagation()
method. Whether or not you stop propagation depends entirely on the specific situation in your code: what type of event is it? Where is the element with the event located? Does this event negatively impact parent events, etc.? Carefully analyze these factors before deciding.
TIP: When stopping propagation, pay attention to which process is active (bubbling or capturing), so you know where to place the method. Capturing, which starts from the root and moves to the target element, is more difficult to stop.
event.stopImmediatePropagation() – Stops bubbling and capturing on parent or child elements and prevents the execution of additional event handlers (for the same event) on the target element. This works starting from IE9.
For example, if the target element has multiple event handlers for the same event, this method stops their execution (after the method is invoked) as well as bubbling and capturing:
// This block of code executes normally $("div").click(function(event){ alert("Event handler 1 executed"); event.stopImmediatePropagation(); }); // These event handlers do not execute, nor does bubbling or capturing $("div").click(function(event){ alert("Event handler 2 executed"); }); $("div").click(function(event){ alert("Event handler 3 executed"); });
Author of the text: bbosko
Add Your Comment