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.

csslayouttutorialintermediate

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.