v147 · CSS · Events
Compatibility Lab
Detects event.pseudoTarget on UIEvent, AnimationEvent, and TransitionEvent. Click the cards to test click origin detection — the log shows whether pseudoTarget resolved a CSSPseudoElement or fell back to a null check. Provides the geometry-fallback pattern for non-supporting browsers.
API probes
Live test: click + animation events
Click anywhere on the blue card, trigger the ★ animation, or run the TIP transition. Toggle forced fallback to inspect the unsupported-browser path without changing browsers.
pseudoTarget detection
CLICK
ANIM
TRANS
event log…
Fallback pattern
/* Detect pseudoTarget support */
const HAS_PSEUDO_TARGET = (() => {
try { return 'pseudoTarget' in new MouseEvent('click'); } catch { return false; }
})();
/* Universal click-origin check */
function isPseudoClick(event, pseudoType) {
if (HAS_PSEUDO_TARGET) {
return event.pseudoTarget?.type === pseudoType;
}
// Fallback: geometry check via Element.pseudo() if available
const el = event.currentTarget;
if (typeof el.pseudo === 'function') {
const pseudo = el.pseudo(pseudoType);
if (!pseudo) return false;
const rect = pseudo.getBoundingClientRect?.();
if (!rect) return false;
return event.clientX >= rect.left && event.clientX <= rect.right &&
event.clientY >= rect.top && event.clientY <= rect.bottom;
}
// Last resort: check if click was within pseudo-element's known region
// (requires layout knowledge of the pseudo-element's position)
return knownPseudoHit(event, el) === pseudoType;
}
function knownPseudoHit(event, el) {
const rect = el.getBoundingClientRect();
const before = { left: rect.left, top: rect.top, right: rect.left + 28, bottom: rect.top + 28 };
const after = { left: rect.right - 28, top: rect.bottom - 28, right: rect.right, bottom: rect.bottom };
if (event.clientX >= before.left && event.clientX <= before.right &&
event.clientY >= before.top && event.clientY <= before.bottom) return '::before';
if (event.clientX >= after.left && event.clientX <= after.right &&
event.clientY >= after.top && event.clientY <= after.bottom) return '::after';
return null;
}
/* Listen for animation events with pseudo attribution */
function onPseudoAnimationEnd(el, pseudoType, callback) {
el.addEventListener('animationend', (e) => {
if (HAS_PSEUDO_TARGET) {
if (e.pseudoTarget?.type === pseudoType) callback(e);
} else {
// Fallback: animationName convention
if (e.animationName === 'beforeSpin') callback(e);
}
});
}
references
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗