Tooltip
Two tiers — a pure :hover/:focus tooltip that works everywhere, and interest-invoker toolbar tips with smart delays and viewport-aware flipping.
interest invokersanchor positioningexit animations
There are two ways to build a tooltip here. The plain-CSS one works in every browser today and is the right default for a lone control. The interest-invoker one is cutting-edge (Chromium only, for now) and earns its keep the moment you have a group of controls, because it can dynamically adjust the display delay.
Plain CSS - maximum compatibility
The safe default. No new platform features, no build caveats, works everywhere.
- A
group/tipwrapper toggles the tip viagroup-hover/tip:andgroup-focus-within/tip:, so keyboard users get it too. delay-100waits a beat before showing, so a cursor passing through doesn’t flash it.pointer-events-nonekeeps the tip from stealing hover and flickering itself.
The trade-off: because it’s positioned by hand, it can’t flip at a viewport edge, so keep tips short. And, as the next section explains, a row of these can’t get the toolbar delay behavior right. For one button in the middle of a form, this is all you need.
Interest invokers - cutting edge, built for groups
The editor-toolbar pattern: the first tooltip waits 300ms, but once one is showing, moving to the next button switches instantly. The delay resets the moment you move the mouse away.
interestforon each button points at its tip, apopover="hint"element. The browser handles showing on hover and keyboard focus, hiding, delays, and the top layer. Nogroup/peerwiring, nopointer-eventsguard.- The delay trick (via Emil Kowalski), written once on the wrapper:
[&>button]:[interest-delay-start:0.3s]makes the first tooltip wait, and[&:has(:interest-source)>button]:[interest-delay-start:0s]zeroes the delay while any sibling already shows interest. Moving between buttons switches tips instantly. The defaultinterest-delay-endkeeps a button’s interest “warm” for a moment after you leave it. That overlap is what makes the switch feel instant, so don’t set it to0s. - Every button declares its own
[anchor-name:--tt-*]and its tip’s[position-anchor:--tt-*]points back at it, so[position-area:top]centers each tip over its own button. [position-try-fallbacks:flip-block]keeps tips on screen: when a tip would poke past the top of the viewport, the browser flips it below the button automatically.
The fallback story
In browsers without interest invokers the toolbar’s hover tips never appear. The buttons
keep their aria-labels, so assistive tech loses nothing. If you need hover tooltips for
everyone today, use the plain-CSS variant. A row of them will then share one fixed
delay rather than the adaptive toolbar timing.
Browser support
Minimum stable version per engine, resolved at build time from MDN's browser-compat-data; Baseline status from the official web-features dataset. Everything degrades gracefully — the “when missing” column is the actual behavior, not a broken page.
| Feature | Chrome | Edge | Firefox | Safari | When missing |
|---|---|---|---|---|---|
| Interest invokers (interestfor + popover="hint")Limited availability | 142 | 142 | ✕ | ✕ | The hover UI simply never appears — triggers keep their aria-labels and links still navigate, so nothing is lost. If you need it everywhere today, the plain-CSS technique on the Tooltip page works in every browser. |
| CSS anchor positioningLimited availability | 129 | 129 | 147 | 26 | The popover opens centered in the viewport (the top-layer default) instead of attached to its trigger. |
| Entry/exit animations (allow-discrete + @starting-style)†Baseline 2024 · newly available | 117 | 117 | 129 | 17.5 | Elements appear and disappear instantly. Nothing breaks — you just lose the animation. |
† @supports cannot test at-rules, so the badge checks transition-behavior: allow-discrete, which co-shipped with @starting-style in every engine.