CSS Anchor Positioning: Tooltip and Dropdown Without JavaScript
Building a tooltip in JavaScript means writing code to calculate the position of the element relative to its trigger, update that position on resize and scroll, handle edge cases when the tooltip ends up outside the viewport, and do all that without introducing layout thrashing. It's not complex, but it's repetitive code that every reinvents application from scratch.
La CSS Anchor Positioning API solves this problem with pure CSS and declarative. With browser support86% global by early 2026 (Chrome 125+, Edge 125+, Chrome for Android, Safari Technology Preview), the technique is mature for production on sites that support modern browsers. Allows to "anchor" one element to another as a reference point for positioning, with automatic fallbacks if there isn't enough space.
What You Will Learn
- The fundamental concepts of CSS Anchor Positioning: anchor, positioned element
- The properties
anchor-nameeposition-anchor - The function
anchor()for relative positioning - How to implement tooltips, dropdowns and context menus in pure CSS
- Automatic fallbacks with
position-try-fallbacks - How to integrate with Popover API for full accessibility
- Progressive enhancement for browsers without support
The Fundamental Concepts
CSS Anchor Positioning introduces two roles:
-
L'anchor element (anchor element): The element to which we anchor.
He receives the property
anchor-namewith a custom identifier value (prefix--). -
Il positioned element (positioned element): the element we want
position relative to the anchor. Must have
position: absoluteoposition: fixed, and receivesposition-anchorto connect to the anchor.
/* 1. Definisci l'ancora */
.button-trigger {
anchor-name: --tooltip-anchor;
}
/* 2. Posiziona l'elemento relativamente all'ancora */
.tooltip {
position: absolute;
/* Collega questo elemento all'ancora */
position-anchor: --tooltip-anchor;
/* Posizionamento usando la funzione anchor() */
/* anchor(bottom) = il bordo bottom dell'ancora */
top: calc(anchor(bottom) + 8px);
/* Centra orizzontalmente rispetto all'ancora */
left: anchor(center);
transform: translateX(-50%);
}
The anchor() Function
The function anchor() resolves to a coordinate relative to the edge
specified element anchor. The available values are:
anchor(top): upper edge of the anchoranchor(bottom): bottom edge of the anchoranchor(left): left edge of the anchoranchor(right): right edge of the anchoranchor(center): horizontal center of the anchoranchor(middle): vertical center of the anchoranchor(self-start),anchor(self-end): related to the direction of the text
/* Tooltip sopra il trigger */
.tooltip-top {
position: absolute;
position-anchor: --my-anchor;
bottom: calc(anchor(top) - 8px);
left: anchor(center);
transform: translateX(-50%);
}
/* Tooltip a destra del trigger */
.tooltip-right {
position: absolute;
position-anchor: --my-anchor;
top: anchor(center);
left: calc(anchor(right) + 8px);
transform: translateY(-50%);
}
/* Dropdown sotto il trigger - allineato a sinistra */
.dropdown {
position: absolute;
position-anchor: --dropdown-anchor;
top: calc(anchor(bottom) + 4px);
left: anchor(left);
min-width: anchor-size(width); /* larghezza minima = larghezza dell'ancora */
}
anchor-size(): Dimensions Relative to the Anchor
In addition to the function anchor() for the coordinates, anchor-size()
allows you to access the dimensions of the element again:
/* Il dropdown ha la stessa larghezza del trigger */
.dropdown {
min-width: anchor-size(width);
/* Altezza massima pari al 50% dell'altezza dell'ancora */
max-height: calc(anchor-size(height) * 0.5);
}
Accessible Tooltip: CSS Anchor + Popover API
The optimal combination for tooltips accessible in 2026 and CSS Anchor Positioning with the Popover API. The Popover API automatically handles focus management, the click-outside to close, and the ARIA accessibility. CSS Anchor Positioning manages visual positioning.
<!-- HTML: Popover API + Anchor Positioning -->
<button
popovertarget="tooltip-content"
class="btn-with-tooltip"
>
Hover per info
</button>
<div
id="tooltip-content"
popover="hint"
class="tooltip"
role="tooltip"
>
Informazione contestuale utile all'utente
</div>
/* CSS: Anchor + Popover */
.btn-with-tooltip {
anchor-name: --btn-anchor;
}
.tooltip {
/* Stili base del tooltip */
position: absolute;
position-anchor: --btn-anchor;
/* Posiziona sotto il pulsante */
top: calc(anchor(bottom) + 8px);
left: anchor(center);
transform: translateX(-50%);
/* Reset stili popover */
margin: 0;
border: 1px solid #e2e8f0;
border-radius: 6px;
padding: 8px 12px;
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
font-size: 0.875rem;
max-width: 280px;
width: max-content;
/* Animazione di entrata */
opacity: 0;
transition: opacity 0.15s ease;
/* Stato visibile (Popover API) */
&:popover-open {
opacity: 1;
}
}
/* Freccia del tooltip */
.tooltip::before {
content: '';
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%);
border: 4px solid transparent;
border-bottom-color: #e2e8f0;
}
.tooltip::after {
content: '';
position: absolute;
top: -7px;
left: 50%;
transform: translateX(-50%);
border: 4px solid transparent;
border-bottom-color: white;
}
Dropdown Full Menu
A more complete example: a dropdown menu from an "Actions" button with CSS Anchor Positioning and Popover API for accessible focus management:
<!-- Bottone trigger -->
<button
class="actions-btn"
popovertarget="actions-menu"
aria-haspopup="true"
>
Azioni ▼
</button>
<!-- Menu dropdown -->
<menu
id="actions-menu"
popover="auto"
class="dropdown-menu"
>
<li><button>Modifica</button></li>
<li><button>Duplica</button></li>
<li class="separator"></li>
<li><button class="danger">Elimina</button></li>
</menu>
/* CSS del dropdown */
.actions-btn {
anchor-name: --actions-anchor;
}
.dropdown-menu {
position: absolute;
position-anchor: --actions-anchor;
/* Allinea il bordo sinistro del menu con il pulsante */
top: calc(anchor(bottom) + 4px);
left: anchor(left);
/* Larghezza minima pari al pulsante */
min-width: anchor-size(width);
/* Reset stili menu */
margin: 0;
padding: 4px 0;
list-style: none;
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
/* Animazione */
opacity: 0;
scale: 0.95;
transform-origin: top left;
transition: opacity 0.15s, scale 0.15s;
&:popover-open {
opacity: 1;
scale: 1;
}
}
.dropdown-menu li button {
display: block;
width: 100%;
padding: 8px 16px;
text-align: left;
border: none;
background: none;
cursor: pointer;
font-size: 0.875rem;
&:hover {
background: #f8fafc;
}
&.danger {
color: #ef4444;
}
}
.dropdown-menu .separator {
height: 1px;
background: #e2e8f0;
margin: 4px 0;
}
Automatic fallbacks with position-try-fallbacks
One of the most tedious problems with tooltips and dropdowns is dealing with cases where there is not enough space: a tooltip that ends up outside the top viewport or on the left must be repositioned automatically.
CSS Anchor Positioning solves this with position-try-fallbacks, that
specifies a list of alternative placements that the browser tests sequentially:
/* Definisci i posizionamenti alternativi */
@position-try --below {
top: calc(anchor(bottom) + 8px);
bottom: auto;
left: anchor(center);
right: auto;
}
@position-try --above {
top: auto;
bottom: calc(anchor(top) + 8px);
left: anchor(center);
right: auto;
}
@position-try --right {
top: anchor(center);
left: calc(anchor(right) + 8px);
right: auto;
bottom: auto;
}
@position-try --left {
top: anchor(center);
right: calc(anchor(left) + 8px);
left: auto;
bottom: auto;
}
.tooltip {
position: absolute;
position-anchor: --my-anchor;
/* Posizionamento default: sotto */
top: calc(anchor(bottom) + 8px);
left: anchor(center);
transform: translateX(-50%);
/* Fallback: prova prima sopra, poi destra, poi sinistra */
position-try-fallbacks: --above, --right, --left;
/* Fallback finale: usa la prima opzione disponibile nel viewport */
position-try-order: most-block-size;
}
Progressive Enhancement for Browsers Without Support
For browsers that do not yet support CSS Anchor Positioning (Firefox stable
does not yet support it as of early 2026 ), uses @supports for
provide a fallback:
/* Fallback: tooltip sempre visibile o con JS */
.tooltip {
/* Stili di default accessibili: mostro un title attribute */
display: none; /* nascosto, gestito da JS fallback */
}
/* Se il browser supporta anchor positioning: CSS puro */
@supports (anchor-name: --test) {
.trigger {
anchor-name: --my-anchor;
}
.tooltip {
display: block; /* visibile, gestito da CSS */
position: absolute;
position-anchor: --my-anchor;
top: calc(anchor(bottom) + 8px);
left: anchor(center);
transform: translateX(-50%);
/* Nascosto di default, mostrato su hover/focus */
opacity: 0;
pointer-events: none;
transition: opacity 0.15s;
}
.trigger:hover + .tooltip,
.trigger:focus + .tooltip {
opacity: 1;
pointer-events: auto;
}
}
/* JavaScript fallback per browser legacy */
if (!CSS.supports('anchor-name', '--test')) {
// Import libreria JS per tooltip
import('./tooltip-fallback.js').then(module => module.init());
}
Firefox: Still Limited Support
As of early 2026, Firefox does not yet support CSS Anchor Positioning in the
stable version (and in active development). This means that 20-25% of
Desktop users on Firefox will see the fallback. USA @supports for
ensure that the experience is always functional, even without anchor positioning.
Next Steps
You now have tooltips and declarative dropdowns in pure CSS. The next article of series explores the View Transitions API: How to implement smooth animations native navigation in the browser, both for Single Page Applications and for Multi-Page Applications, without third-party libraries.
Conclusions
CSS Anchor Positioning is one of the most anticipated additions to the CSS language recent years. It eliminates an entire category of JavaScript code — manual calculation of the positioning coordinates — replacing it with declarative CSS that the browser handles natively, including automatic fallbacks and update on scroll and resize.
With support for 86% of global browsers, you can already adopt it as an enhancement progressive, making sure legacy browsers still have an experience functional. The combination with the Popover API for accessibility management represents the modern and complete stack for building UI overlays in 2026.







