Snippets /
Anchor-positioned tooltip
Tooltip tethered via anchor-name and anchor() — replaces Popper.js.
Quick implementation
/* 1. Name the anchor element */
.trigger { anchor-name: --my-tooltip; }
/* 2. Position the tooltip relative to that anchor */
.tooltip {
position: fixed;
/* Place bottom of tooltip at top of anchor */
inset-block-end: anchor(--my-tooltip top);
/* Center horizontally on anchor */
inset-inline-start: anchor(--my-tooltip center);
translate: -50% -100%;
margin-block-end: 0.4rem; /* gap above anchor */
/* Style */
padding: 0.35rem 0.65rem;
background: oklch(0.18 0.025 260);
color: white; font-size: 0.78rem;
border-radius: 0.375rem; white-space: nowrap;
opacity: 0; pointer-events: none;
transition: opacity 0.15s;
}
.trigger:hover + .tooltip { opacity: 1; }
/* 3. Fallback for unsupported browsers */
@supports not (anchor-name: --x) {
.trigger { position: relative; }
.tooltip {
position: absolute;
bottom: calc(100% + 0.4rem); left: 50%;
translate: -50% 0;
inset-block-end: auto; inset-inline-start: auto;
}
}
Prompt this to your LLM
Includes above/below placement, arrow, and a React variant with Popover API.
You are a senior frontend engineer experimenting with cutting-edge CSS.
Goal: Build a tooltip that uses CSS Anchor Positioning to stay tethered to its trigger — no JavaScript for placement.
Technical constraints:
- Assign anchor-name: --tooltip-trigger on the trigger element.
- On the tooltip: position: fixed; inset-block-end: anchor(--tooltip-trigger top); inset-inline-start: anchor(--tooltip-trigger center); translate: -50% -100%.
- Add a small gap (margin-block-end) between tooltip and trigger.
- Include a CSS triangle arrow using ::after (border trick or clip-path).
- Show/hide with opacity 0 → 1 on :hover (and :focus-visible for keyboard users).
Placement variants:
A) Above (default): inset-block-end at anchor top.
B) Below: inset-block-start at anchor bottom.
Framework / Popover API variant (bonus):
- Pair with the HTML Popover API (<button popovertarget> + <div popover>) so the tooltip has proper open/close state and is accessible by default.
Edge cases to handle:
- Fallback for browsers that don't support anchor(): @supports not (anchor-name: --x) { use position: absolute on a positioned parent instead }.
- Note that anchor-name takes a dashed-ident (e.g. --my-anchor), not a plain name.
- Mention that overflow: hidden on any ancestor will clip the tooltip — use position: fixed to escape stacking contexts.
Return full HTML + CSS with both placement variants and the @supports fallback.
Why this matters in 2026
Floating UI (tooltips, popovers, select dropdowns) has always needed JavaScript for placement — libraries like Popper.js exist entirely for this problem. CSS Anchor Positioning is the native solution: you name an element, and another element positions itself relative to that name. The browser handles scroll, resize, and overflow avoidance.
Browser support is still rolling out (Chrome/Edge, Safari coming), but with a clean @supports fallback it's safe to ship today as a progressive enhancement.
The logic
The anchor element gets anchor-name: --tooltip-trigger (a dashed-ident). The tooltip is position: fixed with logical-property variants: inset-block-end: anchor(--tooltip-trigger top) aligns the tooltip's bottom edge to the trigger's top edge. inset-inline-start: anchor(--tooltip-trigger center) sets its left edge to the trigger's center. Then translate: -50% -100% centers it horizontally and lifts it above.
Using position: fixed means the tooltip escapes any overflow or stacking-context clips on ancestor elements.
Accessibility & performance
Show tooltips on focus-visible too — keyboard users need them. For critical content, don't hide it in a tooltip; tooltips are supplemental. Pair with the Popover API for proper ARIA (popover attribute gives you role and aria-expanded for free). The CSS-only show/hide is GPU-composited — no layout recalc, no JS on the main thread.
@supports not (anchor-name: --x) fallback.