CSS Anchor Positioning now ships in every major browser, making JavaScript tooltip libraries obsolete for most use cases.

Popper.js is 3KB gzipped. Floating UI is 600 bytes for the core, but balloons to 3KB once you add the middleware you actually need. And starting this month, you need exactly zero kilobytes — because CSS can do it natively.

Anchor Positioning Just Shipped Everywhere

Chrome has had CSS Anchor Positioning since version 125 (mid-2024). Firefox shipped it in 131. Safari got it in 18.4, which landed on all Apple devices in March 2026. That means baseline coverage is done. The API that was "experimental" for two years is now just CSS.

The core idea: you declare which element is the "anchor," then position another element relative to it — top, bottom, left, right, with automatic fallback when viewport space runs out. The browser handles the math, the collision detection, and the repositioning on scroll. No JavaScript required.

.trigger {
  anchor-name: --my-tooltip;
}

.tooltip {
  position: fixed;
  position-anchor: --my-tooltip;
  top: anchor(bottom);
  left: anchor(center);
  position-try-fallbacks: flip-block, flip-inline;
}

That position-try-fallbacks line is what previously required an entire JavaScript library. The browser now calculates whether the tooltip would overflow the viewport and flips it automatically.

What This Replaces

If you're using Floating UI, Popper, Tippy.js, or a React wrapper around any of them — this replaces the positioning logic entirely. Not the trigger behavior (hover/focus/click handling), not the animation, not the accessibility attributes. Just the "where does this thing go?" calculation.

That's significant because positioning was the hard part. The part that generated the most bugs, the most performance issues, and the most "why is my tooltip showing up in Antarctica" tickets. Event listeners on scroll, resize, and mutation observers watching the DOM — all of that was compensating for something CSS couldn't express.

The Popover API Handles the Rest

CSS Anchor Positioning tells you where to put it. The Popover API (also baseline 2024, now universal) handles the behavior: showing, hiding, light-dismiss (click outside to close), focus trapping, and top-layer rendering.

<button popovertarget="tip">Hover me</button>
<div id="tip" popover>This is the tooltip content</div>

Combined with anchor positioning, you get a tooltip system with zero JavaScript, zero library dependencies, and behavior that's consistent across browsers because the browser owns it.

Why You Probably Can't Delete Everything Today

Three catches.

Hover timing. CSS :hover triggers instantly. Most tooltip libraries add a 200-300ms delay before showing (and a longer delay before hiding) to avoid flickery behavior when users mouse across a row of icons. You'll need a small CSS transition or a setTimeout wrapper if you care about this. The platform doesn't have a hover-delay property yet.

Accessible descriptions. The Popover API doesn't automatically set aria-describedby on the trigger element. You still need that attribute for screen readers to announce the tooltip content. Floating UI's React component does this automatically. Going native means you're responsible for the ARIA wiring.

Complex positioning chains. Anchor positioning handles one anchor → one positioned element. If you have nested dropdowns where submenu B anchors off menu item A, which itself anchors off button Z — the spec supports this with anchor-name scoping, but the ergonomics aren't as clean as Floating UI's autoUpdate middleware chain.

The Migration Math

For a typical design system with 50-100 tooltip instances:

Factor Library Approach Native CSS
Bundle size 3-8KB gzipped 0KB
Runtime perf scroll/resize listeners browser compositor
Positioning bugs ~monthly edge cases browser-tested
Setup complexity npm install + config CSS properties
Hover delay built-in DIY (3 lines CSS)
ARIA automatic manual

If your tooltips are simple (text label, show on hover, dismiss on leave), the native path wins on every axis except ARIA convenience. If you're building a complex dropdown/popover system with nested menus and keyboard navigation, keep Floating UI — it earns its bytes.

What I'd Actually Do

New project? Start native. Add the ARIA attributes manually — it's 2 lines of HTML per tooltip. If you find yourself fighting the platform (complex nesting, hover timing, animation orchestration), reach for Floating UI's @floating-ui/dom at 600 bytes core.

Existing project with Tippy/Popper? Don't rip it out in a weekend crusade. But stop adding new tooltip instances through the library. Write new ones with anchor positioning + popover. Let the migration happen component by component over a quarter. The library and the native approach can coexist perfectly — they don't conflict.

The tooltip was the last common UI pattern that genuinely required JavaScript for positioning. That era just ended.