Prompt and context
A data-table action button opens a menu or help bubble. The floating panel must follow the button while scrolling, move away from viewport edges, and avoid clipping by ancestors; mobile, keyboard users, and browsers without the new CSS must remain supported. Design this with CSS Anchor Positioning and explain when to retain script or the Popover API.
This question fits frontend, design-system, and component-platform roles. The key is combining geometric placement, overflow fallback, interaction semantics, and compatibility constraints.
What the interviewer evaluates
A strong answer distinguishes an anchor element from an anchor-positioned element and explains how anchor-name, position-anchor, anchor(), or position-area create the relationship. It also covers position-try order, overflow decisions, hiding behavior, scroll containers, stacking contexts, keyboard focus, and fallback.
Clarifications to ask first
- Is the panel a menu, tooltip, picker, or non-interactive explanation? Does it need Popover or dialog semantics?
- What are the preferred and allowed alternate positions, minimum readable size, and safe viewport inset?
- Is the trigger inside a scroll or clipping container, or inside a transformed element?
- Should growing content flip, shrink, scroll internally, or become a full-screen surface?
- Which browsers are targets, and what stable positioning is the older-browser fallback?
A 30-second answer
“I would make the trigger an anchor and the panel an absolutely or fixed-positioned element. I would place it with anchor() or position-area, then declare above and side alternatives with position-try. The component still needs a size limit, viewport inset, focus and dismissal semantics; unsupported browsers use the existing Popover or a measured fallback. I would test scrolling, zoom, long content, keyboard navigation, and viewport edges in both enhanced and fallback modes.”
Step-by-step solution
Step 1: Create the anchor relationship
Expose a name from the trigger with anchor-name, then select it from the panel with position-anchor. For implicit association, verify DOM scope and duplicate-name rules so a repeated row cannot bind to a different button.
Step 2: Choose a placement expression
anchor() reads an anchor edge or center inside inset properties; position-area expresses logical regions such as block-start or inline-end. Both need an explicit position, size limits, and gap rather than one hard-coded pixel offset.
.action {
anchor-name: --action;
}
.menu {
position: absolute;
position-anchor: --action;
top: anchor(bottom);
inset-inline-start: anchor(start);
margin-block-start: 0.5rem;
}Step 3: Declare the fallback order
The default is below the button; when space is insufficient, position-try can test above and the inline-end side. The order should reflect product priority and use logical directions for both left-to-right and right-to-left locales.
.menu {
position-try: flip-block, flip-inline;
max-inline-size: min(90vw, 24rem);
max-block-size: min(70vh, 32rem);
overflow: auto;
}Step 4: Define the impossible-placement state
When every candidate overflows, choose deliberately: shrink and scroll, hide a non-critical hint, or switch to a full-screen surface. Do not leave half a menu outside the viewport or confuse overflow with dismissal.
Step 5: Account for containers and stacking
overflow: hidden, clipping layers, transform, contain, and z-index can change the visible boundary or containing block. Verify the actual positioning context; if needed, render in an appropriate top layer while preserving the trigger-panel relationship.
Step 6: Preserve interaction and accessibility semantics
Anchor Positioning supplies geometry, not menu, tooltip, or popup semantics. Interactive components still need an appropriate role and name, keyboard navigation, Escape dismissal, and focus return; a non-interactive hint must not depend only on hover.
Step 7: Plan the compatibility fallback
MDN marks parts of Anchor Positioning as newer capabilities. Keep a usable default style, then enable enhancement after support detection; older browsers can use the Popover API, an existing component-positioning utility, or a small measured fallback. Do not trade away menu reachability for zero script.
Step 8: Build repeatable validation
Cover all viewport corners, scroll containers, zoom, dynamic text size, long labels, RTL, virtual keyboards, keyboard navigation, and screen readers. Record candidate position, clipping, focus, scroll locking, and layout shift in both supported and fallback environments.
Trade-offs and boundaries
Anchor Positioning moves common tethering and flipping rules into CSS and can reduce per-frame measurement. It remains constrained by browser implementation, positioning context, and component semantics. Complex collision rules, cross-top-layer placement, or business-specific measurements may still require script.
position-try chooses among candidates; it does not guarantee readable content. Size limits, scrolling, focus, and dismissal remain component responsibilities. Popover supplies some interaction behavior but does not replace every menu or dialog design.
Rollout plan and evidence
Pilot one action menu with a preferred position, three fallbacks, a maximum size, and a viewport inset. Record the browser support matrix and keep a stable default placement for unsupported environments.
Document anchor naming, fallback order, logical directions, clipping boundaries, roles, focus, and test cases. Verify position changes with real scrolling and long content instead of relying on static screenshots.
Common mistakes and follow-ups
Writing anchor() without fallbacks
The panel can be clipped at an edge. Declare candidate priorities and define a scrollable or alternate surface when every candidate fails.
Treating placement as interaction semantics
CSS does not turn a panel into a menu or tooltip. Add the role, name, keyboard path, Escape handling, and focus return.
Ignoring scroll and clipping ancestors
A larger z-index cannot escape the wrong containing block. Inspect overflow, transform, contain, and scroll context before changing the rendering layer.
Testing only Chromium
Support matrices evolve. Run the same edge, keyboard, RTL, and long-content cases in enhanced and fallback modes.
What if the panel is still unreadable?
Check candidate positions and maximum size first, then choose internal scrolling, shrinking, a full-screen surface, or hiding non-critical content; do not simply raise z-index or disable overflow checks.