# Reorder List

> A list you put in order, like an on-call order or a meeting's running order. Drag a row by its handle, or pick it up with Space and move it with the arrows.

- Name: `reorder-list`
- Status: beta
- Categories: data, display
- File: the install writes `reorder-list.tsx` to your `ui` alias, `@/components/ui` by default.
- npm packages: `lucide-react`. The install adds them.
- Other registry items: `@arbokui/button`, `@arbokui/motion-timing`, `@arbokui/person`, `@arbokui/tool-button`, `@arbokui/tooltip`. The install adds them.
- Gallery: https://arbokui.com/components/reorder-list
- Registry item: https://arbokui.com/r/reorder-list.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/reorder-list
   ```

## Use it for

- An on-call order, a meeting's running order, agenda items: one short list, in a Card.
- Pass items with an id each. A person shows with their photo. Anything else shows its label and meta, or your renderItem.
- Keep the order in state with onReorder. It hands back your own objects, in their new order, after each drop.
- Tell people about the new order in onSettle. It runs once the 8-second ⌘Z window ends, so ⌘Z never takes back a message already sent.
- Turn on numbered when the rank matters. Ranks and dividers belong to the slots and stay put while rows move.
- Set disabled once the order is final, like once the order is sent. The handles go, so it no longer looks as if it could move.

## Avoid it for

- Placing people onto a team sheet's positions. That is a slot for each position, like PositionSlot.
- Long lists that scroll. A drag does not scroll the page for you.
- Your own undo button or timer. Each drop joins the page's ⌘Z stack, and moves made within 8 seconds undo together.

## Props

- `items`: `T[] where T extends { id: string; person?: string; photo?: string; label?: string; meta?: string }`. The rows, in order.
- `onReorder`: `(items: T[]) => void`. The items in their new order after each drop, and the order before when ⌘Z puts it back.
- `onSettle`: `(items: T[]) => void`. The order is final: its ⌘Z window ended. Tell people here.
- `renderItem`: `(item: T, index: number) => ReactNode`. Row content. Default a Person for people, otherwise the label and meta.
- `numbered`: `boolean`. Default `false`. Shows each rank at the row's left.
- `label`: `string`. Names the list, like "On call, in order".
- `disabled`: `boolean`. Default `false`. Locked. The rows show no handles.
- `className`: `string`. Extra classes. Later classes win.

## Accessibility

- The list is an ordered list named by label, so screen readers say each row's place.
- Each row's handle is a button named "Move" and the row's name. The handles share one Tab stop, and ↑↓, Home, and End move between them.
- Space picks the focused row up, and its handle reads as pressed. ↑↓ move it, Home and End take it to the ends, Space or Enter drops it, and Esc puts it back.
- A row that is up owns Esc, even inside a Sheet. The next Esc closes the sheet.
- Focus leaving a row that is up drops it where it is.
- A polite live region says each step: picked up, each place it passes, and where it dropped or went back.
- Every drag has the same moves on the keys. A mouse lifts a row after 4 px, a finger after holding still for 350 ms, and Esc cancels a drag.
- Reduced motion turns off the glide. The rows step to their new places.

## Examples

### A running order

```tsx
const [plan, setPlan] = useState(PLAN);

<Card className="gap-0 py-1.5">
  <ReorderList items={plan} label="Tuesday's agenda, in order" numbered onReorder={setPlan} onSettle={save} />
</Card>
```

### People in ranked order

```tsx
<ReorderList
  items={[
    { id: "sam", person: "Sam Carter", meta: "Engineering" },
    { id: "noah", person: "Noah Kerr", meta: "Engineering" },
  ]}
  label="On call, in order"
  numbered
  onReorder={setOnCall}
/>
```
