Blocks

Reorder List

Reorder rows by dragging them into the gap between neighboring items.

Installation

pnpm dlx @mielui/svelte add reorder-list

Usage

Bind items for live movement and give each item a stable id with getId and a spoken name with getLabel. Use onCommit to persist, so a drag writes once rather than on every crossing. Drag the handle with a mouse, pen, or touch; row content stays interactive.

External changes to list membership or order cancel the active gesture. Cancel restores the original order of items that still exist. It keeps updated item data and items added during the gesture.

<script lang="ts">
    import * as ReorderList from '@mielui/svelte/components/reorder-list';

    let items = $state([
        {
            id: 'lint',
            name: 'Lint'
        },
        {
            id: 'test',
            name: 'Test'
        },
        {
            id: 'deploy',
            name: 'Deploy'
        }
    ]);
</script>

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

Composition

With children, each row renders ReorderList.Item with a Handle before Content. Pass row instead to arrange those parts yourself; every row needs an Item with its stable id and accessible label. Drag the handle, or focus it and press Space, to pick up a row. Keep links and buttons in Content, outside the handle.

<ReorderList.Root
    bind:items
    getId={(item) => item.id}
    getLabel={(item) => item.name}
    label="Priority"
>
    {#snippet row(item)}
        <ReorderList.Item id={item.id} label={item.name}>
            <ReorderList.Content>{item.name}</ReorderList.Content>
            <ReorderList.Handle />
        </ReorderList.Item>
    {/snippet}
</ReorderList.Root>

Examples

Agenda with reset

A Reset button restores the starting order, and a hint explains the keyboard controls.

Handle after content

Save and lock the order

Events and disabling

onReorder runs with the new array after every move, from a drag or the keyboard. onCommit runs once when a move is dropped or confirmed; save the final array there. Keyboard users can lift a row, move it, and press Escape to cancel without saving a partial order. disabled on Root locks the list: rows stay visible and nothing can be moved.

Labels

Built-in text is English by default. Pass a labels object of type ReorderListLabels to translate the keyboard hint and the announcements made while a row moves: hint, grabbed, moved, dropped, cancelled, and cancelledByChange. Every key is optional; omitted keys keep their default.

<script lang="ts">
    import type { ReorderListLabels } from '@mielui/svelte/components/reorder-list';

    const labels: ReorderListLabels = {
        hint: 'Faites glisser pour rรฉordonner.',
        dropped: (item, position) => `${item} dรฉposรฉ en position ${position}.`
    };
</script>

<ReorderList.Root bind:items {getId} {getLabel} label="Prioritรฉs" {labels}>
    โ€ฆ
</ReorderList.Root>

API reference

ReorderList.Item

  • id Required
    string

    The item's id from getId. It is not applied as the element's DOM id.

  • label Required
    string

    Name of the item, used as the handle's accessible name.

ReorderList

Reorders controlled items with pointer or keyboard input.

  • labels
    ReorderListLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

  • items Required Bindable
    unknown[]

    Items in their current order. Bindable.

  • getId Required
    (item: unknown) => string

    Returns a stable id for an item.

  • getLabel Required
    (item: unknown) => string

    Returns the name announced for an item.

  • children
    Snippet<[unknown]>

    Renders an item's content beside the default handle.

  • row
    Snippet<[unknown]>

    Replaces the default row. Compose Item, Handle, and Content inside it.

  • label Required
    string

    Accessible name of the list.

  • disabled
    boolean

    Prevents interaction and dims the control.

    Default false

  • onReorder
    ((items: unknown[]) => void)

    Called with the new order on every move.

  • onCommit
    ((items: unknown[]) => void)

    Called once when a move is dropped or confirmed.

  • class
    (string & (ClassValue | null))

    Classes added to the element.

Other parts

These parts have no props of their own. They pass HTML attributes and events to their element.

  • ReorderList.Content
  • ReorderList.Handle