Radial Stagger
StaggerRadial stagger — grid tiles spring in, ordered by their distance from a center point.
Click any tile to ripple outward from it.
Installation
One command drops the source into your repo — editable, with the provider and motion pulled in automatically.
npx shadcn add https://motion.asmitsah.dev/r/radial-stagger.jsonThis component imports from @/lib/motion and needs <MotionProvider> mounted in your root layout — install the base once, before copying this component.
npx shadcn add https://motion.asmitsah.dev/r/provider.jsonnpm install motioncomponents/motion/radial-stagger.tsxUsage
Basic
Decorative by default — tiles are non-focusable role="presentation" cells. Clicking one re-ripples the cascade from it.
Distance metric
Switch how ring distance from the origin is measured — "manhattan" ripples in diamonds, "chebyshev" in squares, "euclidean" (default) in circles.
Interactive tiles
Opt into real focusable buttons — each tile needs an accessible name via getItemLabel, or you ship nameless controls (WCAG 4.1.2).
Tuned step + origin
Raise `step` for a slower, more dramatic cascade; set `defaultOrigin` to start the first ripple somewhere other than tile 0.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | One child per grid tile — each pops in on its own ring delay. |
| className | string | — | Classes for the grid container (RadialStagger sets display:grid + columns via style). |
| style | CSSProperties | — | Inline style passthrough, merged onto the grid. |
| itemClassName | string | — | Classes applied to every tile (the grid cell). |
| columns | number | 4 | Grid columns — drives both the layout and the ring-distance geometry. |
| step | number | feel.stagger (0.08) | Seconds of delay added per unit of distance from the origin tile. |
| distance | "euclidean" | "manhattan" | "chebyshev" | "euclidean" | How ring distance from the origin cell is measured. |
| defaultOrigin | number | 0 | Index the first cascade ripples out from, before any click. |
| interactive | boolean | false | Renders tiles as focusable `<button>`s instead of decorative role="presentation" elements. Requires `getItemLabel`. |
| getItemLabel | (index: number) => string | — | Accessible name for the tile at `index` — required when `interactive`. |
| onSelect | (index: number) => void | — | Fires with the tile index when an interactive tile is selected. |