Anchor Positioning
The Problem
Positioning elements relative to other elements — tooltips, popovers, dropdown menus, labels — has always required JavaScript. Libraries like Floating UI (Popper.js) calculate positions, handle viewport overflow, and reposition on scroll/resize. This adds bundle size, complexity, and frame-rate concerns. AI agents consistently recommend JavaScript positioning libraries when pure CSS anchor positioning would be more performant and maintainable.
The Solution
CSS Anchor Positioning lets you declaratively position an element relative to an "anchor" element using pure CSS. It handles the anchor relationship (anchor-name / position-anchor), positioning (position-area or the anchor() function), and automatic fallback repositioning when the element overflows the viewport (position-try-fallbacks). Combined with the Popover API, this replaces most JavaScript tooltip/dropdown libraries.
Code Examples
Basic Tooltip
.anchor-button {
anchor-name: --my-tooltip-anchor;
}
.tooltip {
/* Attach to the anchor */
position: fixed;
position-anchor: --my-tooltip-anchor;
/* Position above the anchor, centered */
position-area: top center;
/* Spacing from the anchor */
margin-bottom: 8px;
/* Styling */
background: #1f2937;
color: white;
padding: 0.5rem 0.75rem;
border-radius: 6px;
font-size: 0.875rem;
white-space: nowrap;
}
<button class="anchor-button">Hover me</button>
<div class="tooltip" popover="hint">Helpful tooltip text</div>
Dropdown Menu
.menu-trigger {
anchor-name: --menu-anchor;
}
.dropdown-menu {
position: fixed;
position-anchor: --menu-anchor;
/* Below the trigger, left-aligned */
position-area: bottom span-right;
margin-top: 4px;
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 0.25rem;
min-width: 180px;
}
<button class="menu-trigger" popovertarget="dropdown">Menu</button>
<div class="dropdown-menu" id="dropdown" popover>
<button>Option 1</button>
<button>Option 2</button>
<button>Option 3</button>
</div>
Automatic Fallback Positioning
When the positioned element would overflow the viewport, automatically try alternative positions.
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
position-area: top center;
margin: 8px;
/* If top overflows, try bottom, then right, then left */
position-try-fallbacks: flip-block, flip-inline;
}
Custom Fallback Positions with @position-try
@position-try --below {
position-area: bottom center;
margin-top: 8px;
}
@position-try --right {
position-area: right center;
margin-left: 8px;
}
@position-try --left {
position-area: left center;
margin-right: 8px;
}
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Default: above */
position-area: top center;
margin-bottom: 8px;
/* Try these in order if default overflows */
position-try-fallbacks: --below, --right, --left;
}
Using the anchor() Function for Precise Placement
For more control than position-area provides, use the anchor() function inside inset properties.
.popover {
position: fixed;
position-anchor: --trigger;
/* Position the popover's top-left corner at the anchor's bottom-left corner */
top: anchor(bottom);
left: anchor(left);
/* Or center horizontally relative to anchor */
left: anchor(center);
translate: -50% 0;
}
Connecting Label to Form Field
.form-field {
anchor-name: --field;
}
.field-hint {
position: fixed;
position-anchor: --field;
position-area: right center;
margin-left: 12px;
font-size: 0.75rem;
color: #6b7280;
max-width: 200px;
}
<div>
<input class="form-field" type="email" placeholder="Email" />
<p class="field-hint">We'll never share your email.</p>
</div>
Dynamic Anchors with anchor-name on Multiple Elements
.list-item {
anchor-name: --item;
}
.list-item:hover {
/* The detail panel follows whichever item is hovered */
}
.detail-panel {
position: fixed;
position-anchor: --item;
position-area: right center;
margin-left: 1rem;
}
Combining with Popover API
[popovertarget] {
anchor-name: --popover-trigger;
}
[popover] {
position: fixed;
position-anchor: --popover-trigger;
position-area: bottom center;
margin-top: 4px;
/* Automatic fallback */
position-try-fallbacks: flip-block;
/* Styling */
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 1rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
<button popovertarget="info-popover">Info</button>
<div id="info-popover" popover>
<h3>Additional Information</h3>
<p>This popover is positioned and managed entirely in CSS/HTML.</p>
</div>
Browser Support
- Chrome 125+
- Edge 125+
- Safari 26+ (Technology Preview, shipping 2025-2026)
- Firefox 145+ (behind a flag), fully shipped in Firefox 150+
As of late 2025, anchor positioning is available in all major browsers. For older browsers, the CSS anchor positioning polyfill by OddBird supports Chrome 51+, Firefox 54+, and Safari 10+. Always provide a reasonable non-positioned fallback.
Common AI Mistakes
- Recommending JavaScript positioning libraries (Floating UI, Popper.js) for tooltips and popovers when CSS anchor positioning handles it natively
- Not knowing that CSS anchor positioning exists
- Using
position: absolutewith manualtop/leftcalculations instead ofposition-area - Forgetting
position: fixedon the anchored element (required for anchor positioning to work) - Not using
position-try-fallbacksfor viewport overflow handling — the element gets clipped - Confusing the old
inset-areaproperty name with the currentposition-area(renamed in Chrome 129) - Not combining anchor positioning with the Popover API for accessible disclosure patterns
When to Use
- Tooltips, popovers, and info panels positioned relative to a trigger
- Dropdown menus that need to reposition when near viewport edges
- Form field hints and validation messages positioned beside inputs
- Floating labels and annotation markers
- Any UI pattern that previously required JavaScript to position one element relative to another