Pseudo-classes are states, not events
Iris Calderón
You wired up a pointerenter listener on a card so it lifts when the cursor arrives, then a matching pointerleave to put it back. The span between those two events, the whole period the cursor is over the card, already has a name in CSS. It is called :hover. The new CSS-Tricks piece is a useful nudge that most of those listeners shouldn't be there in the first place.
The framing the article reaches for is sharper than the usual "use CSS where you can". Pseudo-classes aren't event handlers the browser ships for free. They're states. A state has a beginning, a duration, and an end. An event is a moment. The pseudo-class captures the period bracketed by two events, not either event in isolation.
The state lives between two events
The clearest mapping is also the most underrated.
:hover matches the period between pointerenter and pointerleave. :active matches while the element is being pressed with a mouse, finger or stylus. That is the window between pointerdown and pointerup (or pointercancel).
You can fight this. Attach four pointer listeners, juggle a boolean per card, toggle a class. Or pick the pseudo-class that already tracks the same boolean and skip the bookkeeping. The cascade resolves the visual state. JavaScript is left for things that actually need a script: a network call or a route change.
Worth keeping next to that: pointer-events: none is the property that stops pointer events firing on the element at all. It is the deliberate opt-out, not a side effect of styling.
A small one-liner the article uses, since we're here:
form:has(:focus) {
/* Style the form when something within has focus */
}
:focus-within does the same job. :has() generalises it: any condition you can write as a selector, you can scope to the ancestor. The "I need a wrapper class for that" reflex shrinks with every release.
:focus-visible is a heuristic, not a quieter :focus
This is where the state framing pays off.
:focus-visible triggers when :focus does. The browser then decides, using heuristics, whether to show the focus indicator at all. Was the user driving with a keyboard? Is the focused element a form control that always wants the ring? The pseudo-class is the spec's way of letting authors hook into that browser-side judgement, not into the raw event.
You cannot reproduce that with addEventListener('focus', …). A focus event tells you focus moved. It does not tell you whether the user would benefit from the ring. The pseudo-class does.
When CSS itself starts listening
The flipside is the proposed event-trigger syntax in the Animation Triggers spec. The idea is to let CSS bind an animation to an event, not to the state the event implies. The article cites the proposed shape:
button {
event-trigger: --event click;
}
The named event then becomes available as an trigger for an animation:
div {
animation-trigger: --event play-forwards;
animation: fade-in 300ms both;
}
This is the part where the line actually moves. CSS interactivity has been purely declarative state up to now: be in this state, look like this. With event-trigger, CSS gets a way to react to a moment instead of a span. The spec also sketches stateful pairings such as --event interest / interest for entry-and-exit triggers.
It is a proposal. No browser ships it today. Be honest about that on your next PR.
What to try on your next view
Audit one component. Anywhere a pointerenter or pointerleave listener exists purely to add a class, the pseudo-class is sitting right there. Anywhere a focus listener flips a wrapper into a "has-focus" mode, :focus-within or form:has(:focus) does it with no state to track.
The ergonomic win per call site is small. Across a codebase it is the difference between something that needs hydration and something the browser renders correctly on first paint.
The pattern this kills is "JS for interaction, CSS for paint". The honest split is "CSS for states, JS for events that actually need a script". Treat event-trigger as the future case where even that line moves. Keep an eye on the Animation Triggers spec while you wait.
Source: CSS-Tricks (css-tricks.com)