Radio Traveling Dot
One shared dot glides to the checked radio with anchor(), with no script. Browsers without anchor positioning keep the radios' own ring.
Reduced Motion
Your system is set to reduce motion, so the animations shown on this page will not play for you.
Code
The following example assumes that you have imported the component and set up the theme.
<div class="traveling-dot" aria-label="Notifications" role="radiogroup">7 collapsed lines
<sv-radio checked name="notifications" value="instant">Instantly</sv-radio> <sv-radio name="notifications" value="daily">Daily digest</sv-radio> <sv-radio name="notifications" value="weekly">Weekly summary</sv-radio> <sv-radio name="notifications" value="never">Never</sv-radio>
<!-- The dot comes after the radios, because an anchor must be laid out first. --> <span class="dot" aria-hidden="true"></span></div>
<style>52 collapsed lines
.traveling-dot { --ring-size: 1.3em; --dot-size: 0.6em;
position: relative; display: grid; gap: 0.9em; inline-size: fit-content; padding-block: 1.5em; margin-inline: auto;
sv-radio { --sv-radio-sz: var(--ring-size); }
.dot { display: none; }
@supports (anchor-name: --checked-radio) { sv-radio { --sv-radio-active-bdr-sz: 1.5px; }
sv-radio:state(--checked) { anchor-name: --checked-radio; }
.dot { position: absolute; inset-block-start: calc(anchor(center) - var(--dot-size) / 2); inset-inline-start: calc(anchor(start) + (var(--ring-size) - var(--dot-size)) / 2); inline-size: var(--dot-size); block-size: var(--dot-size); position-anchor: --checked-radio; pointer-events: none; background-color: var(--sv-accent); border-radius: 50%; transition: inset 450ms cubic-bezier(0.3, 1.3, 0.5, 1); }
&:has(sv-radio:state(--checked)) .dot { display: block; } }
@media (prefers-reduced-motion: reduce) { .dot { transition-duration: 0s; } } }</style>