# Stagger

> Shows its children fading up one after another as they first appear, for lists, card grids, and sections on page load.

- Name: `stagger`
- Status: beta
- Categories: motion, layout
- File: the install writes `stagger.tsx` to your `ui` alias, `@/components/ui` by default.
- Gallery: https://arbokui.com/components/stagger
- Registry item: https://arbokui.com/r/stagger.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/stagger
   ```

## Use it for

- A list, a grid of cards, or the sections of a page that arrive together, so the eye reads them in order.
- Wrap the items once: \<Stagger className="grid gap-4">{cards}\</Stagger>. Each child becomes one item.
- Put the layout classes on Stagger. Each child is wrapped in a \<div>, so the wrappers are the grid or flex items.
- Pass as="ul" or as="ol" for a list. Each child is then wrapped in an \<li>, so pass the content, not \<li> elements.
- Only the first eight items step, 35ms apart. The rest arrive with the eighth, so a long list is whole in under half a second.

## Avoid it for

- Menus, selects, and other popups. Their items appear at once, in one piece.
- Content that updates often, like a live feed. Only new items fade in, and the wait between them reads as lag.
- Wrapping a single element. There is nothing to put in order.
- Nesting Staggers. The inner items wait on top of the outer wait.

## Props

- `children`: `ReactNode`. The items. Each child fades up in turn, wrapped in a \<div>, or an \<li> in a list.
- `step`: `number`. Default `35`. Milliseconds between items in the default feel. Calm and Playful stretch it with their durations, and motion off makes it 0.
- `delay`: `number`. Default `0`. Milliseconds before the first item, scaled the same way as step.
- `as`: `"div" | "section" | "ul" | "ol"`. Default `"div"`. The element that holds the items. With ul or ol, each item is an \<li>.
- `className`: `string`. Classes on the outer element, like a grid or a gap.

## Accessibility

- Nothing is hidden from screen readers while it fades. Every item is in the page from the first render.
- Reduced motion takes out the rise, so items only fade in place. With motion off, every item shows at once.
- It uses CSS @starting-style, so it needs no script. Browsers without it show every item at once.
- With as="ul" or as="ol", it is a real list, so screen readers say how many items there are.

## Examples

### A grid of cards (needs @arbokui/card)

```tsx
import { Card } from "@/components/ui/card";

<Stagger className="grid gap-4 sm:grid-cols-3">
  {teams.map((team) => (
    <Card key={team.id} className="h-full px-4">
      {team.name}
    </Card>
  ))}
</Stagger>
```

### A list

```tsx
<Stagger as="ul" className="flex flex-col gap-2">
  {members.map((member) => (
    <span key={member.id}>{member.name}</span>
  ))}
</Stagger>
```

### Slower, after the page title

```tsx
<Stagger step={60} delay={120} className="flex flex-col gap-6">
  <section>…</section>
  <section>…</section>
</Stagger>
```
