Smart CSS Anchored Selection Pills
See the Pen Smart CSS Anchored Selection Pills.
Tech & Dependencies
Features
- ✓ Anchor Positioning
- ✓ Mask Composition
- ✓ Tweakpane Config
- ✓ Progressive Enhancement
Browser Support
Core
This Smart CSS Anchored Selection Pills component demonstrates the bleeding edge of CSS layout capabilities. It uses the new CSS Anchor Positioning API to tether a visual “pill” indicator to the currently selected radio button without JavaScript calculations for position. The demo includes a robust fallback system that calculates positions via ResizeObserver for browsers that don’t yet support anchors, ensuring a consistent experience across the board. It also features advanced masking techniques (SVG and CSS Filters) to create “knockout” text effects where the selected text changes color inversely to the pill background.
Core Technique
The implementation showcases two distinct strategies for positioning the selection indicator:
Native CSS Anchors: When supported, the
.pillelement is positioned relative to the focused/checked label usingposition-anchor: --active. The CSStop,left,width, andheightproperties useanchor()functions (e.g.,top: anchor(top)). This delegates all layout logic to the browser’s layout engine, resulting in zero-latency updates during resizing or reflows.JavaScript Fallback (Polyfill-like behavior): For browsers without anchor support, a
ResizeObservermonitors the container. When the layout changes or an input is clicked, JavaScript calculates thegetBoundingClientRectof the selected label relative to the container and updates CSS custom properties (--top,--left,--width,--height) on the parent. The.pillthen uses these variables for positioning.
Additionally, a creative “Knockout” Effect is achieved using either mask-image with a dynamically generated SVG (updated via JS on resize) or CSS filter: url(#knockout-black) with feColorMatrix to invert colors based on the background luminance.
Customization
The component is highly configurable via the Tweakpane control panel in the demo, but in code, you can adjust the transition physics and styles in the CSS layers.
@layer anchor {
@supports (anchor-name: --active) {
.pill {
/* Link pill dimensions to the anchor */
top: anchor(top);
left: anchor(left);
width: anchor-size(width);
height: anchor-size(height);
position-anchor: --active;
/* Smooth transition for movement */
transition-property: left, top, width;
transition-duration: calc(var(--duration, 0.2) * 1s);
transition-timing-function: ease-out;
}
/* Define the anchor on the label preceding the checked input */
label:has(+ :checked) {
anchor-name: --active;
}
}
}
To modify the “knockout” text color logic, check the SVG filter definitions in the HTML. The matrix values determine how colors are shifted.
Tips
1. Progressive Enhancement First:
This snippet is a perfect example of progressive enhancement. It checks CSS.supports('anchor-name: --active') before executing heavy JavaScript layout logic. This means users on modern browsers get a lighter, performant experience, while others still get full functionality.
2. Handling Dynamic Content:
If your labels change size (e.g., loading different text or fonts), the ResizeObserver is crucial even with Anchor Positioning for edge cases where layout shifts might desynchronize complex masks. The demo handles this by observing the entire container.

