Unsaved Changes

You have unsaved changes to this preset. How do you want to proceed?

Insert Component

⌘K

CSS Anchor Positioning Kills the Tooltip Library

Most tooltip libraries ship between 40 and 80 kB of JavaScript to solve a problem CSS has had an answer to since 2023. That problem: positioning one element relative to another element that isn't its parent.

How it works

Three CSS properties handle the whole thing. anchor-name marks the reference element with a custom identifier. position-anchor connects the floating element to it. anchor() reads the reference element's edges to compute offsets.

Diagram showing a trigger element with anchor-name and a tooltip positioned with position-anchor and anchor()
anchor-name on the trigger, position-anchor and anchor() on the tooltip. Three properties, no JavaScript.
.trigger {
  anchor-name: --my-tooltip;
}

.tooltip {
  position: absolute;
  position-anchor: --my-tooltip;
  top: anchor(bottom);
  left: anchor(center);
  translate: -50% 8px;
}

What you were doing before

Before this, you'd call getBoundingClientRect() on the trigger, add scroll offsets, check viewport edges, and set top and left in a useEffect. Libraries like Floating UI automate that calculation. The calculation was always the wrong abstraction.

const rect = trigger.getBoundingClientRect();

setPosition({
  top: rect.bottom + window.scrollY + 8,
  left: rect.left + window.scrollX + rect.width / 2,
});
Floating UI is well-built. You shouldn't need it for tooltips.

Browser support

Browser support: Chrome 125+, Firefox 130+, Safari 18.4+
Full support across the three major engines as of late 2024.

Anchor positioning has full support in Chrome 125+ and Firefox 130+. Safari ships it in Safari 18.4. For older Safari, the @oddbird/css-anchor-positioning polyfill covers the spec with a 12 kB footprint, cheaper than the library it replaces.


When to use it

Use anchor positioning for tooltips, popovers, dropdowns, and any UI where one element needs to track another without JavaScript. Skip it when you need collision detection across nested scroll containers; Floating UI still handles that better.