Reorder List

Rows trade places as you drag, so the list shows the new order before you drop. With the keyboard, Space or Enter grabs a row, Up and Down move it, and Escape restores the original order.

Drag to reorder. With the keyboard, Space or Enter grabs the row, the arrow keys move it, Space or Enter drops it, and Escape restores the original order.

Drag a row, or focus it and press Space to grab it. Arrow keys move; Escape cancels.

<script lang="ts">
    import { Button } from '@sivir-ui/svelte/components/button';
    import { ReorderList } from '@sivir-ui/svelte/components/reorder-list';

    type AgendaItem = { id: string; name: string; duration: string };
    const initial: AgendaItem[] = [
        { id: 'opening', name: 'Opening remarks', duration: '5 min' },
        { id: 'roadmap', name: 'Roadmap review', duration: '15 min' },
        { id: 'critique', name: 'Design critique', duration: '20 min' },
        { id: 'questions', name: 'Open questions', duration: '10 min' }
    ];
    let items = $state([...initial]);
</script>

<div class="w-full max-w-md">
    <div class="mb-3 flex justify-end">
        <Button size="md" variant="ghost" onclick={() => (items = [...initial])}>Reset</Button>
    </div>
    <ReorderList
        bind:items
        getId={(item) => item.id}
        getLabel={(item) => item.name}
        label="Meeting agenda"
    >
        {#snippet children(item)}
            <span class="flex min-w-0 items-center justify-between gap-4">
                <span class="truncate text-sm font-medium">{item.name}</span>
                <span class="shrink-0 text-xs tabular-nums text-foreground-muted"
                    >{item.duration}</span
                >
            </span>
        {/snippet}
    </ReorderList>
    <p class="mt-3 text-xs leading-relaxed text-foreground-muted">
        Drag a row, or focus it and press Space to grab it. Arrow keys move; Escape cancels.
    </p>
</div>

Installation

Copy the command below and run it in your terminal.

bunx @sivir-ui/svelte add reorder-list

Usage

Bind items. It updates, and onReorder fires, each time a row passes a neighbor. Save from onCommit, which fires once on drop. Row content is hidden from screen readers, so getLabel supplies the text announced for each row. Rows can be dragged from anywhere with a mouse, pen, or touch.

import { ReorderList } from '@sivir-ui/svelte/components/reorder-list';

let steps = $state([
  { id: 'build', name: 'Build' },
  { id: 'test', name: 'Test' },
  { id: 'deploy', name: 'Deploy' }
]);

<ReorderList bind:items={steps} getId={(item) => item.id} getLabel={(item) => item.name} label="Pipeline steps" onCommit={saveOrder}>
  {#snippet children(item)}
    <span>{item.name}</span>
  {/snippet}
</ReorderList>

Anatomy

ReorderList - Reorders controlled items with pointer or keyboard input.