---
title: Reorder
description: The drag handle and the move-up and move-down arrows for one row of a list Livewire sorts, so a keyboard and a screen reader can reorder it too.
visibility: guest
draft: false
---

# Reorder

A list whose order the reader sets, like the values of a product attribute or the steps of a
checklist, takes Livewire's `wire:sort` on the list and `wire:sort:item` on each row. A `reorder`
in each row then carries the handle a pointer drags and two arrow buttons for everyone else:
nobody can drag with a keyboard or a screen reader, and anybody can press a button. The arrows
call the same method a drop calls, so one method serves both.

It fits in any row: a list item, a card, a cell of a grid. Rows of a
[table](/components/table#reordering-rows) take `table.reorder`, which draws the same controls as
a table cell.

:::preview{title="A list reordered by dragging or with the arrows"}
<livewire:demos.reorder-host :rows="[['Small'], ['Medium'], ['Large']]" />
:::

:::source{language="blade"}
{{-- In your app there is no host: your own Livewire component renders the rows and owns the method. --}}
<x-wirekit::list type="none" spacing="md" wire:sort="moveValue">
    @foreach ($values as $value)
        <x-wirekit::list.item wire:sort:item="{{ $value->id }}" wire:key="value-{{ $value->id }}">
            <x-wirekit::row gap="sm">
                <x-wirekit::reorder :item="$value->id" :position="$loop->index" :count="$loop->count" action="moveValue" :label="$value->name" />
                <x-wirekit::text>{{ $value->name }}</x-wirekit::text>
            </x-wirekit::row>
        </x-wirekit::list.item>
    @endforeach
</x-wirekit::list>
:::

```php
// 1. Called by a drop and by both arrows: the row's key and its new position, from 0
public function moveValue(int $id, int $position): void
{
    // 2. Store the new order, then render the rows in it
}
```

## The Ends of the List

`position` and `count` disable the arrows that lead nowhere: the first row cannot move up, the
last cannot move down. Without `count`, nothing here knows which row is last, so the down arrow
of the last row stays enabled and calls the method with a position past the end.

## Naming the Row

`label` names the row in the arrows' names, "Move Medium up". That matters wherever the row does
not say what it is next to the arrows, and in a long list, where a screen reader moving from arrow
to arrow otherwise hears "Move up" for every row.

## Arrow Surface and Size

The arrows are neutral icon buttons, `ghost` at size `xs` unless told otherwise. `arrow-surface`
and `arrow-size` take any surface and size a [button](/components/button) takes, so an
application whose icon buttons are `soft` draws its arrows the same way:

:::preview{title="Arrows in the soft surface"}
<x-wirekit::row gap="sm">
    <x-wirekit::reorder :item="4" :position="1" :count="3" action="moveValue" label="Medium" arrow-surface="soft" arrow-size="sm" />
    <x-wirekit::text>Medium</x-wirekit::text>
</x-wirekit::row>
:::

## Lists Inside Lists

The focus comes back to the arrow in the list it was pressed in, and that list is the element
holding the row that carries `wire:sort:item`. Two lists on one page can share their row keys, and
a list can sit inside a row of another one, without the focus landing in the wrong list.

::: warning
A drag reorders the rows in the browser before its request leaves, so the order on screen does
not tell you whether the server has taken it. Each `reorder` carries the position the server drew
in `data-wk-reorder-position`: a test that waits for those to match the new order waits for the
server's answer, not for the browser's guess.
:::

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `item` | mixed | `null` | The row's key, the value its row carries in `wire:sort:item` |
| `position` | int | `0` | Where the row stands, counted from 0 |
| `count` | int\|null | `null` | How many rows there are. Without it the down arrow is never disabled |
| `action` | string | `null` | The Livewire method the list's `wire:sort` calls. The arrows call it with the row's key and its new position |
| `label` | string\|null | `null` | What the row is, for the arrows' names — see [Naming the Row](#naming-the-row) |
| `arrowSurface` | string | `'ghost'` | The arrows' button surface: `filled`, `outline`, `soft`, `ghost` or `link` |
| `arrowSize` | string | `'xs'` | The arrows' button size: any size a [button](/components/button) takes |
| `scope` | string\|null | `null` | Scoped personalization name |

## Accessibility

- **The arrows are how a keyboard and a screen reader move a row.** Each is a button named for
  what it does, "Move up" and "Move down", or "Move Medium up" with a `label`. The name is the
  button's own text, hidden visually, and the tooltip shows the same words to a pointer.
- **The handle carries `aria-hidden="true"`.** Dragging is not something a keyboard or a screen
  reader can do, and the two buttons beside it are their way to the same result.
- **An arrow that leads nowhere is disabled**, so it is skipped by the Tab key rather than
  announced as a button that does nothing.

## Keyboard Interaction

| Key | Action |
| --- | --- |
| `Tab` | Moves to the next arrow. The handle is not focusable |
| `Enter` / `Space` | Presses the focused arrow, which moves the row one place |

After the server answers, the focus is back on the arrow that was pressed, in the row's new place,
or on the other arrow once the row has reached an end. A row can be moved several places by
pressing the same key again. A reader who moved on during the round trip keeps where they went.

## Design Tokens

| Element | Token |
| --- | --- |
| Handle | `--color-wk-text-subtle`, and `--color-wk-text-muted` on hover |
| Space between handle and arrows | `--gap-wk-xs` |
| Arrows | the [button](/components/button#design-tokens) tokens of their surface and size |

## Further Reading

- [Table](/components/table#reordering-rows) — the same controls as a table cell
- [List](/components/list) — the list the example above uses
- [Button](/components/button) — the surfaces and sizes the arrows take
