CSS Anchor Positioning: No More JavaScript Tooltips
Attach a tooltip or dropdown to another element in CSS, with fallback positions when the preferred side has no room.
I've shipped the same tooltip logic in three codebases: measure the trigger with getBoundingClientRect(), place the panel, re-measure on scroll and resize. It works until someone puts the trigger in a scrolling container, and the panel drifts from the button.
Anchor positioning moves all of that into CSS.
What Is Anchor Positioning?
One element becomes the anchor. A second declares it's positioned against it.
/* Step 1: Name the anchor */
.button {
anchor-name: --my-button;
}
/* Step 2: Position the tooltip relative to it */
.tooltip {
position: absolute;
position-anchor: --my-button;
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}The translate: -50% pulls the tooltip back by half its width, since anchor(center) aligns left edges. Miss it and the tooltip sits 40px right.
What It Replaces
Tooltips and dropdowns stop needing a positioning library. The browser tracks the anchor through scrolling, so the panel follows the button instead of drifting away from it. And position-try gives you fallback positions when the preferred direction has no room.
Most of the bugs in my old tooltip code were scroll bugs.
The position-try Fallback System
You define a few alternatives and the browser uses the first that fits. A tooltip that would overflow the bottom flips above the button:
@position-try --flip-above {
bottom: anchor(top);
top: unset;
}
.tooltip {
position: absolute;
position-anchor: --my-button;
top: anchor(bottom);
position-try-fallbacks: --flip-above;
}You can list several fallbacks; the browser tries them in order. I haven't tested many at once.
Real-World Use Cases
- Tooltips and popovers: the example everyone starts with.
- Select dropdowns: custom selects that open near their trigger.
- Context menus: right-click menus anchored to a zero-size element at the cursor.
- Floating labels: labels that stay attached to their inputs.
Minimal Working Example
<button class="trigger">Hover me</button>
<div class="tooltip" popover>I am anchored!</div>.trigger {
anchor-name: --trigger;
}
.tooltip {
position: fixed;
position-anchor: --trigger;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
margin: 0;
}The tooltip uses position: fixed rather than absolute. With popovers, that's usually the version that behaves.
Browser Support
As of early 2025, anchor positioning is available in Chrome 125+ and Edge 125+. Firefox and Safari are still implementing it, so gate the CSS with @supports (anchor-name: --x) and keep the old solution as a fallback.
Worth adopting, but I'd keep the JS fallback in production for now.