Custom notebooks for your e-ink tabletSupernote, reMarkable and more.Build yours →

CSS Anchor Positioning for Tooltips

Tooltip positioning without JavaScript

The old way relied on JS libraries like Popper.js or Floating UI to compute tooltip position. CSS anchor positioning ties the tooltip to its trigger with anchor-name and position-anchor.

Old way10+ lines
/* JS: getBoundingClientRect for trigger + tooltip,   compute top/left, handle scroll/resize */.tooltip   {  position: fixed;  top: var(--computed-top);  left: var(--computed-left);}
Modern
9 lines
.trigger   {  anchor-name: --tip;}.tooltip   {  position: absolute;  position-anchor: --tip;  position-area: top;}/* the browser keeps it above the trigger */
Limited availability87% global usage

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Not ready for production without a fallback.

129+
147+
26+
129+

Everything on this page works in Chrome and Edge 129, Firefox 147 and Safari 26. Baseline still lists anchor positioning as limited because only Safari supports every position-visibility value, which this snippet doesn't use.

hover the button to see the tooltip
CSS-only tooltip ✦

No layout thrash

The browser keeps tooltip and trigger in sync. No JS measuring or scroll listeners.

Declarative

You say where the tooltip goes relative to the anchor. The engine does the math.

Drop the library

Popper.js and Floating UI are great, but for simple tooltips you can skip them entirely.

Lines Saved
10+ → 9
No JS positioning
Old Approach
JS libraries
Popper.js, Floating UI
Modern Approach
CSS anchor positioning
anchor-name, position-area

How it works

The old way was to use a library like Popper.js or Floating UI: JavaScript reads the trigger and tooltip rects, computes top/left, sets them (often via CSS variables or inline styles), and subscribes to scroll and resize to update. It works but adds weight and complexity.

The modern way is CSS anchor positioning. Give the trigger anchor-name: --tip, then give the tooltip position-anchor: --tip and position-area: top. position-area places the tooltip on a 3 by 3 grid around the trigger, so top, bottom span-right or left replace the offset math. When you need exact edges, anchor() still works, as in top: anchor(bottom).

The part that saves the most code is position-try-fallbacks. Add position-try-fallbacks: flip-block and a tooltip that would overflow the top of the viewport moves below the trigger instead. That replaces the flip logic most positioning libraries are used for.

Anchor positioning handles placement only. Show/hide still needs a toggle. Pair it with the popover attribute on the tooltip and popovertarget on the trigger for a fully accessible, zero-JS show/hide pattern. For full modal dialogs, the <dialog> element handles this natively. Use @supports (anchor-name: --x) to gate styles for older browsers.

ESC