Positioning a popover, tooltip, dropdown menu, or contextual panel next to a button has traditionally required a combination of CSS positioning and JavaScript calculations. Developers often need to measure an element's dimensions, calculate its coordinates, account for scrolling, and adjust its position when the viewport changes.
For simple interfaces, this approach can introduce unnecessary complexity. A dropdown might appear in the wrong place after scrolling, a tooltip could extend beyond the viewport, or a popover might require additional JavaScript to remain aligned with its trigger.
CSS Anchor Positioning provides a browser-native way to position one element relative to another. Instead of manually calculating coordinates, developers can establish an anchor element and use CSS properties to position a related element around it.
This article explains how CSS Anchor Positioning works, how to implement popovers and tooltips, how to handle positioning constraints, and what to consider before using it in production.
What Is CSS Anchor Positioning?
CSS Anchor Positioning is a CSS feature that allows one element to be positioned relative to another element designated as its anchor.
Consider a button that opens a contextual menu. The button is the anchor, and the menu is the positioned element.
With traditional CSS, developers might use JavaScript to calculate the button's position and update the menu's top and left values. With Anchor Positioning, CSS can establish the relationship directly.
The main concepts include:
anchor-name: Assigns a name to an element that can serve as an anchor.
position-anchor: Connects a positioned element to a named anchor.
anchor(): References an anchor's position when calculating CSS inset values.
position-area: Places a positioned element in an area relative to its anchor.
position-try-fallbacks: Defines alternative positions when the preferred placement does not fit.
These properties can reduce the amount of JavaScript required for interface positioning.
Browser support varies by property and browser version, so check the support requirements for your target audience before adopting the feature.
Create a Simple Popover With CSS Anchor Positioning
Start with a button and a panel that should appear directly below it.
Step 1: Define the Anchor Element
The button needs an anchor name so that another element can reference it.
<div class="toolbar">
<button id="help-button" type="button">
Help
</button>
<div class="help-popover">
Find answers to common questions here.
</div>
</div>
The button acts as the anchor, while the help-popover element is the panel that will be positioned relative to it.
Step 2: Connect the Popover to the Anchor
Use the anchor-name property on the button and position-anchor on the popover.
#help-button {
anchor-name: --help-anchor;
}
.help-popover {
position: absolute;
position-anchor: --help-anchor;
position-area: bottom;
margin: 0;
width: 240px;
padding: 12px 16px;
background: white;
border: 1px solid #d1d5db;
border-radius: 8px;
box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
}
Here is what the important declarations do:
anchor-name: --help-anchor assigns a named anchor to the button.
position: absolute takes the popover out of normal document flow.
position-anchor: --help-anchor connects the popover to that anchor.
position-area: bottom places the popover in the area below the anchor.
The browser handles the positional relationship without requiring JavaScript to calculate the button's coordinates.
The example demonstrates positioning only. The panel's visibility and interaction behavior must also be implemented.
Control Visibility With the Popover API
CSS Anchor Positioning determines where an element appears, but it does not independently provide a complete open-and-close interaction.
For a simple contextual panel, the HTML Popover API can handle visibility without a custom JavaScript toggle.
<div class="toolbar">
<button
id="help-button"
type="button"
popovertarget="help-popover">
Help
</button>
<div
id="help-popover"
class="help-popover"
popover>
Find answers to common questions here.
</div>
</div>
The corresponding CSS is:
#help-button {
anchor-name: --help-anchor;
}
.help-popover {
position: absolute;
position-anchor: --help-anchor;
position-area: bottom;
margin: 8px 0 0;
padding: 12px 16px;
width: 240px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: white;
box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
}
The popovertarget attribute connects the button to the popover. Clicking the button opens or closes the panel through the browser's built-in behavior.
The Popover API and CSS Anchor Positioning solve different problems:
Combining them reduces the need for custom positioning and visibility logic.
For production interfaces, verify that the popover's default styles and placement work with your layout. You may need additional styling to meet your design requirements.
Position a Popover Above, Below, or Beside an Element
The position-area property allows developers to place a positioned element around its anchor without manually setting every coordinate.
For example:
.popover-below {
position: absolute;
position-anchor: --help-anchor;
position-area: bottom;
}
.popover-above {
position: absolute;
position-anchor: --help-anchor;
position-area: top;
}
.popover-right {
position: absolute;
position-anchor: --help-anchor;
position-area: right;
}
.popover-left {
position: absolute;
position-anchor: --help-anchor;
position-area: left;
}
These examples assume that the corresponding anchor name is defined on the intended anchor element.
The browser uses the selected position area to determine where the positioned element should appear relative to the anchor.
This approach is useful for tooltips, contextual actions, help panels, and compact navigation menus.
Use anchor() for More Precise Positioning
Sometimes a component needs more control than a predefined position area provides.
The anchor() function can reference a specific edge of the anchor when setting inset properties.
For example:
.help-popover {
position: absolute;
position-anchor: --help-anchor;
top: anchor(bottom);
left: anchor(left);
margin-top: 8px;
}
This places the popover's top edge relative to the bottom edge of the anchor and aligns its left edge with the anchor's left edge.
The anchor() function is useful when a design requires precise alignment. However, it does not automatically solve every viewport overflow problem. Fallback positioning and layout constraints may still be necessary.
Prevent Popovers From Going Outside the Viewport
A common positioning problem occurs when an element is placed near the bottom or edge of the viewport.
For example, a menu positioned below a button near the bottom of the screen may extend beyond the visible area.
CSS Anchor Positioning supports fallback strategies that allow the browser to try alternative placements.
Define Alternative Positions
Consider a menu that should appear below its anchor whenever possible but move above it when necessary.
#menu-button {
anchor-name: --menu-anchor;
}
.context-menu {
position: absolute;
position-anchor: --menu-anchor;
position-area: bottom;
margin: 8px 0 0;
position-try-fallbacks: flip-block;
width: 220px;
padding: 8px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: white;
}
The flip-block fallback instructs the browser to try an alternative placement along the block axis when the preferred placement cannot fit.
In a typical horizontal writing mode, this means the menu can try moving from below the anchor to above it.
Other fallback strategies can be configured depending on whether the component needs to move horizontally, vertically, or use a custom set of alternative placements.
Use Custom Fallback Positions
For more specific layouts, define named fallback styles using @position-try.
.context-menu {
position: absolute;
position-anchor: --menu-anchor;
position-area: bottom;
position-try-fallbacks: --menu-above;
margin: 8px 0 0;
}
@position-try --menu-above {
position-area: top;
margin: 0 0 8px;
}
The browser first attempts the preferred placement below the anchor. If the placement does not fit according to the relevant positioning rules, it can try the custom alternative above the anchor.
The fallback should account for spacing as well as placement. Otherwise, the menu may appear on the correct side but overlap the anchor or create an inconsistent visual gap.
Fallback behavior should be tested with different viewport sizes, scrolling positions, and menu dimensions.
Handle Multiple Anchors on the Same Page
Applications often contain multiple buttons that can open contextual panels. Each positioned element must reference the correct anchor.
For example, a table may contain an action button for every row. Assigning every button the same global anchor name can create ambiguous relationships when several matching anchors exist.
A simple page with distinct components can use separate anchor names:
<div class="profile">
<button id="profile-button" type="button">
Profile
</button>
<div class="profile-panel">
Profile settings
</div>
</div>
<div class="notifications">
<button id="notifications-button" type="button">
Notifications
</button>
<div class="notifications-panel">
Notification settings
</div>
</div>
#profile-button {
anchor-name: --profile-anchor;
}
.profile-panel {
position: absolute;
position-anchor: --profile-anchor;
position-area: bottom;
}
#notifications-button {
anchor-name: --notifications-anchor;
}
.notifications-panel {
position: absolute;
position-anchor: --notifications-anchor;
position-area: bottom;
}
Each panel references a distinct anchor.
For repeated components, generate unique anchor names when appropriate or use a component architecture that guarantees the intended anchor relationship. Avoid relying on ambiguous names when several instances are rendered together.
Also consider how the application handles multiple simultaneously open panels. Anchor Positioning does not automatically decide which menu should be open or close competing menus.
CSS Anchor Positioning vs. JavaScript-Based Positioning
Both approaches can be useful, but they solve the problem differently.
Consideration | CSS Anchor Positioning | JavaScript-based positioning |
|---|
Basic anchor relationship | Defined in CSS | Calculated in JavaScript or delegated to a library |
Viewport fallback | Supported through CSS fallback mechanisms | Must be implemented or provided by a library |
Scroll and resize handling | Browser manages the CSS positioning relationship | May require observers, event listeners, or library support |
Custom collision behavior | Depends on supported CSS positioning features | Can support complex application-specific rules |
Browser compatibility | Depends on browser support for the required features | Depends on the chosen JavaScript and library APIs |
Complex interactive layouts | May need additional CSS and interaction logic | Can provide more control over complex behavior |
CSS Anchor Positioning is a good option when the relationship between the anchor and the positioned element can be expressed through CSS.
JavaScript positioning libraries remain useful for advanced layouts involving complex collision handling, custom interaction rules, nested floating elements, or compatibility requirements that cannot be met with the available CSS features.
The decision should depend on the application's supported browsers and actual positioning requirements rather than on a general preference for CSS or JavaScript.
Common Mistakes and Troubleshooting
The Popover Appears in the Wrong Location
Check that the positioned element references the intended anchor name.
#help-button {
anchor-name: --help-anchor;
}
.help-popover {
position: absolute;
position-anchor: --help-anchor;
position-area: bottom;
}
A spelling mismatch or incorrect anchor relationship can prevent the intended positioning behavior.
Also inspect surrounding styles that may affect the positioned element's layout.
The Popover Is Not Visible
Anchor Positioning does not automatically open a hidden panel.
If you use the HTML Popover API, verify that the trigger has the correct popovertarget value and that the target element has the popover attribute.
If the panel is controlled by application state, confirm that the relevant visibility logic is working independently of the positioning styles.
The Popover Extends Beyond the Viewport
A preferred placement may not fit in a narrow viewport or near a screen edge.
Configure appropriate position-try-fallbacks or custom @position-try rules. Also constrain the panel's dimensions when necessary.
For example:
.context-menu {
max-width: min(320px, calc(100vw - 24px));
max-height: 60vh;
overflow: auto;
}
These constraints limit the panel's dimensions, while anchor fallback rules help determine where it should appear.
Multiple Panels Reference the Wrong Anchor
Review anchor names in repeated components. Distinct components may require distinct anchor names or a carefully designed naming strategy.
Test the behavior when multiple buttons exist in the same container and when several panels can be opened.
The Feature Works in One Browser but Not Another
CSS Anchor Positioning support varies across browser versions and individual features.
Check the target browser matrix for anchor-name, position-anchor, position-area, and any fallback features used by the application. Do not assume that support for one part of the feature guarantees support for every related property.
If older browsers are part of the support requirements, provide a suitable fallback layout or use an established JavaScript positioning solution.
Best Practices for Production Applications
Keep Positioning and Interaction Separate
Use CSS Anchor Positioning to define where the element appears. Use the Popover API or application logic to control when it opens and closes.
This separation makes the component easier to understand and maintain.
Design for Narrow Viewports
Test popovers on small screens, not just desktop monitors. Menus may need width constraints, scrolling, or alternative placements to remain usable.
Avoid Unnecessary JavaScript Calculations
If CSS can express the required anchor relationship and fallback behavior, avoid adding coordinate calculations that duplicate the browser's positioning work.
However, do not remove an existing positioning library until you have verified that CSS can handle the component's full behavior.
Consider Keyboard and Screen Reader Users
Positioning does not automatically make a popover accessible.
Use semantic HTML, meaningful labels, appropriate focus behavior, and keyboard interaction patterns. Ensure users can reach and dismiss interactive content without relying exclusively on pointer input.
For interactive menus and dialogs, follow the appropriate accessibility pattern rather than treating every popover as the same component type.
Test Real Layout Conditions
Test the component with scrolling containers, dynamic content, browser zoom, responsive layouts, and different viewport dimensions.
A popover that works with a short text label may behave differently when its content becomes much longer or when the anchor is close to the edge of the visible area.
Advantages and Limitations
Advantages
Reduces the need for JavaScript-based coordinate calculations.
Expresses relationships between elements directly in CSS.
Supports alternative placement strategies for constrained layouts.
Works well with contextual panels, tooltips, and dropdown-style interfaces.
Can simplify maintenance when positioning requirements are relatively straightforward.
Limitations
Browser support must be verified for the required properties.
Positioning alone does not implement interaction or accessibility behavior.
Complex floating layouts may still require JavaScript.
Multiple anchors require careful naming and component design.
Fallback behavior must be tested against actual layout conditions.
Conclusion
CSS Anchor Positioning provides a native way to position one element relative to another without manually calculating coordinates in JavaScript. By using anchor-name, position-anchor, position-area, and fallback rules, developers can build contextual panels and popovers with less positioning code.
When combined with the HTML Popover API, it can also reduce the JavaScript needed for basic open-and-close behavior.
For production applications, verify browser support, define sensible fallback positions, test repeated components, and implement accessibility independently of the positioning logic. Use JavaScript when the interface requires behavior that cannot be expressed reliably through the available CSS features.
The result is a more declarative approach to building floating UI elements, with fewer manual calculations and a clearer separation between layout and interaction.
Join the conversation! Your thoughts help the community grow.