Radial Nav
betaNavigation on a ring around a hub: an arc indicator springs to the active item the short way round, and the hub cross-fades to its icon and label.
- Navigation
- 1 file
- 2 npm packages
- Accessibility notes
- Animates with motion
Loading the example…
pnpm dlx @dowel-ui/cli add radial-navnpm packages installed: class-variance-authority, motion.
import { RadialNav } from "@/components/ui/radial-nav";Default
Sizes
Links
Controlled
<RadialNav>
| Prop | Type | Default |
|---|---|---|
items (required)The items, clockwise from the top. | RadialNavItem[] | — |
defaultValueUncontrolled initial active item id. Defaults to the first. | string | — |
onValueChange | (id: string) => void | — |
size | "sm" | "md" | "lg" | "md" |
valueControlled active item id. | string | — |
Plus every attribute of <nav> except defaultValue, children.
A <nav> (named by aria-label, "Main" by default, or aria-labelledby) around a real list. With href each item is a link and the active one carries aria-current="page"; without, items are toggle buttons and the active one is aria-pressed. Every item is named by its label in visually hidden text. The list is one Tab stop with a roving tabindex: ArrowRight/ArrowDown move forward round the ring and ArrowLeft/ArrowUp back (Left/Right swap in right-to-left), wrapping, and Home/End jump to the first and last. The track, indicator, hub and hover captions are aria-hidden; the active item is also set apart by its fill, so the indicator is never the only signal. Springs run through motion inside MotionConfig reducedMotion="user"; nothing moves on first paint, and under reduced motion the indicator jumps.
10/10
checks passed
- Tested — passes
- axe assertion — passes
- Keyboard tested — passes
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — passes
- className merged — passes
- Visible focus — passes
- No fixed widths — passes