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.
/* JS: getBoundingClientRect for trigger + tooltip, compute top/left, handle scroll/resize */.tooltip { position: fixed; top: var(--computed-top); left: var(--computed-left);}.trigger { anchor-name: --tip;}.tooltip { position: absolute; position-anchor: --tip; position-area: top;}/* the browser keeps it above the trigger */anchor positioning Browser Support
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.
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.
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.
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.
