Event Retargeting in the Browser
Event retargeting adjusts the target exposed to listeners as an event crosses a Shadow DOM boundary. It preserves encapsulation while allowing event propagation to continue, and is distinct from bubbling and the `composed` property.
Event retargeting is the browser's adjustment of an event's target as the event crosses a shadow DOM boundary. A listener inside a component's shadow tree may see an internal element as `event.target`, while a listener outside that tree sees the shadow host instead.
This adjustment preserves component encapsulation: outside code can react to an event without necessarily learning which internal node produced it. With nested shadow trees, the exposed target can be adjusted at each boundary according to where the listener is located.
Retargeting does not mean the event stops propagating. Propagation behavior depends on properties such as `bubbles` and `composed`; `composed: true` allows an event to cross a shadow boundary. The target adjustment is a separate concern from whether the event bubbles.
`event.composedPath()` is useful when investigating propagation. It returns the path visible from the current listener's context; nodes inside a closed shadow root are not exposed to outside listeners. Related target values, such as `relatedTarget` on pointer transitions, can also be adjusted to avoid revealing shadow-tree details or exposing misleading transitions.
Key points
- A listener's position relative to a shadow tree affects the target it observes.
- Outside listeners can see the shadow host as `event.target` for an event originating inside the shadow tree.
- Retargeting is distinct from bubbling and from whether an event is composed.
- `composedPath()` provides a listener-context view of the event path.
- Closed shadow roots do not expose their internal path nodes to outside listeners.
Interview questions
What is event retargeting in the context of Shadow DOM?
Retargeting adjusts the target exposed to a listener when an event crosses a shadow DOM boundary. A listener within the shadow tree can see the originating internal element, while an outside listener generally sees the shadow host. This supports encapsulation without necessarily stopping propagation.
How do `bubbles`, `composed`, and retargeting differ?
`bubbles` controls propagation through ancestors during the bubbling phase, while `composed` controls whether an event may cross a shadow DOM boundary. Retargeting adjusts the target that listeners see across that boundary. These are distinct aspects of event behavior, so an event's target, propagation, and boundary crossing should be considered separately.
How does `composedPath()` relate to `event.target`?
`event.target` is the target exposed to the current listener after any applicable retargeting. `event.composedPath()` gives the propagation path visible from that listener's context, which can help explain how the event traveled. For a closed shadow root, outside listeners do not get its internal nodes in that path. Neither API should be treated as a way for outside code to inspect all closed-root internals.
Can retargeting affect properties other than `event.target`?
Pointer events can include a `relatedTarget` describing the other endpoint of a transition, such as the element being entered or left. Like `target`, related-target values may be adjusted at shadow boundaries. This helps avoid exposing internal nodes and can prevent outside listeners from seeing transitions that are not meaningful at their level. Code that relies on transitions should test behavior at the listener's actual boundary rather than assuming the internal nodes are visible.