v147 · shipped · dom · events
Pseudo target on events
Chrome 147 adds a pseudoTarget property to UIEvent, AnimationEvent, and TransitionEvent. When an event originates from a CSS pseudo-element such as ::before or ::after, pseudoTarget returns the corresponding CSSPseudoElement object rather than null, letting event handlers distinguish pseudo-element interactions without relying on hit-test workarounds.
at a glance
| Shipped in | Chrome 147 (desktop, Android, WebView) |
|---|---|
| Status | Enabled by default |
| New property | Event.pseudoTarget |
| Returns | CSSPseudoElement or null |
| Spec | CSS Pseudo-Elements Level 4 |
| ChromeStatus | 5179328935624704 — Pseudo target on events |
why it exists
CSS pseudo-elements like ::before and ::after generate rendered content and are fully interactive — they receive pointer events, fire animation events, and participate in transitions. Before Chrome 147, Event.target always referred to the originating DOM element, with no way to tell programmatically that the interaction happened on a pseudo-element rather than the element itself. Developers resorted to geometry calculations or layout mirrors to infer the hit. pseudoTarget closes this gap directly in the event object.
shape of the API
The pseudoTarget property
Every UIEvent, AnimationEvent, and TransitionEvent now carries a pseudoTarget property:
- If the event was dispatched on a pseudo-element,
pseudoTargetis aCSSPseudoElementwhosetypeis the pseudo-element selector (e.g."::before") and whoseelementis the originating DOM element. - If the event was not dispatched on a pseudo-element,
pseudoTargetisnull. Event.targetremains the originating DOM element in both cases — existing code is unaffected.
Supported event types
| Interface | Typical events |
|---|---|
UIEvent | click, pointerdown, focus, keydown, … |
AnimationEvent | animationstart, animationend, animationiteration |
TransitionEvent | transitionstart, transitionend, transitionrun |
Note: mouseover, mouseout, mouseenter, mouseleave, and their pointer* hover counterparts are not yet supported.
example
Detecting a click on ::after
const box = document.querySelector('.box');
box.addEventListener('click', (event) => {
if (event.pseudoTarget !== null) {
console.log('Clicked on pseudo-element:', event.pseudoTarget.type);
// e.g. "::after"
console.log('Originating element:', event.pseudoTarget.element);
} else {
console.log('Clicked on the element itself');
}
});
Reacting to a transition on ::before
document.addEventListener('transitionend', (event) => {
if (event.pseudoTarget?.type === '::before') {
// A ::before pseudo-element finished its CSS transition
const host = event.pseudoTarget.element;
host.classList.remove('transitioning');
}
});
Source: blink-dev Intent to Ship — Pseudo target on events, April 2026.
browser support
| Browser | Support |
|---|---|
| Chrome 147+ (desktop, Android, WebView) | Enabled by default |
| Firefox | No signal |
| Safari | No signal |