Utilities✨ Premium

CSS Anchor Tooltip Pro

Tooltips attached to their button with CSS Anchor Positioning: they switch sides at the window edge, close with Escape and stay readable everywhere.

Anchor PositioningTooltipCSS moderne

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Loan simulator — the two key amounts say what they include — CSS Anchor Tooltip Pro example 1

① Loan simulator — the two key amounts say what they include

WhenOn Banque Méravon's results page, rates and fees sit on the sides; in the middle, hovering or keyboard-selecting "Monthly payment" or "Total cost" opens a dark tooltip that says in one sentence what the amount includes.
WhyThe two amounts that matter have their explanation at hand without cluttering the page. The monthly payment's tooltip opens below, the total cost's above, in the free band between them: nothing gets covered. The whole card is the button, a large target for a finger or a mouse.
SettingsMonthly payment in atp-bottom, total cost in atp-top; each whole card is the button (label, amount, "i" mark). --tip-bg: #132036, a light --tip-fg, --tip-width: 230px. Both cards sit on the capture mouse's path, which hovers them in turn.
Festival site map — one marker per place, the tooltip avoids the edges — CSS Anchor Tooltip Pro example 2

② Festival site map — one marker per place, the tooltip avoids the edges

WhenOn the Calvessa festival map, every marker (stages, welcome desk, first aid, water point, shuttles) is a button. On hover or when tabbing through the markers, a dark label gives the place's name and the useful detail: "Main stage · Tonight 9:30 pm".
WhyThe markers go right up to the edges of the map: the lake stage marker, against the right edge, opens its tooltip to the left, the top one opens it below, without a single line of positioning code. The map stays readable at rest; details only show on demand.
SettingsMarkers in atp-top, atp-right or atp-left depending on where they sit; --tip-bg: #1f2a1c, --tip-width: 300px, text on one line (white-space: nowrap in the scene). The markers are off the capture mouse's path: the scene moves keyboard focus to four of them in turn (focus({ focusVisible: true })).
Avatars on a shared document — each person's name and access — CSS Anchor Tooltip Pro example 3

③ Avatars on a shared document — each person's name and access

WhenAt the top of a welcome guide written together in Plumarelle, four round badges show who has access to the document. On hover or focus, each one gives its name and access: "Tom Arnaud · Can edit · section 2", "Inès Carvalho · Comments".
WhyInitials are not enough to recognise someone: the tooltip fills in without taking room in the header. Sitting at the top of the window, tooltips asked for above have no room and flip below on their own.
SettingsPairs in atp-top flipped below by position-try-fallbacks; 36 px avatars with the full name as hidden text inside the button; --tip-bg: #1e2430, text on one line. Keyboard focus moved by the scene to each avatar in turn for the capture.

How it works

Each .atp-btn button is followed by its .atp-tip tooltip inside an .atp-pair that sets the wanted direction: atp-top, atp-bottom, atp-left or atp-right. The tooltip shows when the button or the tooltip itself is hovered, and on keyboard focus (:focus-visible), with a 0.18 s fade; hidden, it is visibility: hidden.

When the browser knows CSS Anchor Positioning, the script gives each button a unique anchor name (anchor-name) and ties it to its tooltip (position-anchor). The tooltip then switches to position: fixed with position-area: it follows its button anywhere on the page and, if the window lacks room on that side, position-try-fallbacks flips it to the other (top ↔ bottom, left ↔ right). On each opening, the script records the actual side in data-atp-side to put the small arrow on the right side.

Without Anchor Positioning (older browsers) or without JavaScript, the same tooltip is placed with position: absolute around its button, on the intended side, with no flipping. Escape closes the open tooltip without moving the mouse or the focus; it comes back once you leave the button and return.

Accessibility

  • Tied to its button: the script gives each tooltip a unique id and sets it in the button's aria-describedby. The screen reader reads the button name, then its description.
  • Truly hidden at rest: visibility: hidden takes closed tooltips out of reading; the description stays available through aria-describedby.
  • Dismissible and hoverable (WCAG 1.4.13): Escape closes it; the mouse can move from the button onto the tooltip to read or select its text without it vanishing.
  • Reduced motion: under prefers-reduced-motion: reduce, the 4 px slide goes away, leaving a plain fade.
  • Touch: tapping the button shows the tooltip (hover emulated by the browser), tapping elsewhere usually closes it. Do not put essential information only in a tooltip: on mobile it stays easy to miss.

Browser compatibility

CSS Anchor Positioning (anchor-name, position-area, position-try-fallbacks): Chrome 129, Firefox 147, Safari 26; before that, automatic fallback to simple placement. Maximum width in container units (cqw): Chrome 105, Firefox 110, Safari 16. About 2 KB of JavaScript for the anchor names, aria-describedby, Escape and the arrow. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): 4 directions in 2 copies, flipping at the window edges, forced fallback without Anchor Positioning, Escape on hover and on focus, mouse moving onto the tooltip, code pasted twice, touch, 390 px, reduced motion, 0 errors.

Chrome 129+✓ Full (measured)
Firefox 147+✓ Full (measured in Firefox 153)
Safari 26+✓ Full (measured in WebKit 26.5)
Edge 129+✓ Full (Chromium engine)
Mobile iOS 26+✓ WebKit engine, not checked on a device
Older browsers✓ Fallback: tooltip on the intended side, no flipping (measured)

Without Anchor Positioning or without JavaScript, the tooltip stays on its intended side even near an edge, where it may overflow. Without JavaScript there is no aria-describedby and no closing with Escape.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0787-root">
  <div class="atp-demo">
    <div class="atp-pair atp-bottom">
      <button class="atp-btn" type="button">Bottom</button>
      <p class="atp-tip" role="tooltip">Below the button…</p>
    </div>
    <div class="atp-pair atp-right">…</div>
    <div class="atp-pair atp-left">…</div>
    <div class="atp-pair atp-top">…</div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Direction (HTML — class of .atp-pair) atp-top, atp-bottom, atp-left, atp-right The tooltip's preferred side; it moves to the opposite side when the window lacks room (with Anchor Positioning).
Colours (CSS — --tip-bg, --tip-fg) #6d5efc and #fff Background and text of the tooltip and its arrow; set on the root or on a single pair.
Gap (CSS — --tip-offset) 10px Distance between button and tooltip. Above 14 px, moving the mouse onto the tooltip becomes less reliable.
Maximum width (CSS — --tip-width) min(220px, 44cqw) Beyond it the text wraps. Add white-space: nowrap for short single-line labels.
Cross demo (HTML/CSS — .atp-demo) 4 buttons around an empty centre Drop this container in your page: pairs work anywhere inside the root.

FAQ

The same tooltip, placed around its button on the intended side, with Escape and aria-describedby. Only the flip near an edge is missing: close to the window edge, the tooltip may then overflow.
Yes with Anchor Positioning: it is position: fixed and placed against the window, so a parent that clips its content does not cut it (unless that parent has a transform or a filter). In fallback mode it is position: absolute and may be clipped.
No. A tooltip (role="tooltip") only holds text, and focus cannot be moved into it. For links or buttons, use a popup opened on click.