SortableList
A list that reorders by drag or keyboard.
Usage
Basic
Every item needs a stable string id; the item slot's dragging flag marks the carried row.
Loading demo...
Drag Modes
The default pointer mode carries the row while the others spring aside; use dragMode="native" when items must leave the list, as in board columns.
<template>
<TxSortableList v-model="column.cards" drag-mode="native" />
</template>
Drag Handle Mode
handle requires a drag to start inside [data-tx-sort-handle="true"]. Default rows include a grip; a custom slot spreads handleAttrs onto its own.
<template>
<TxSortableList v-model="steps" handle @reorder="saveOrder">
<template #item="{ item, handleAttrs }">
<div>
<button type="button" v-bind="handleAttrs" aria-label="Drag item">☰</button>
<span>{{ item.title }}</span>
</div>
</template>
</TxSortableList>
</template>
Persisting Reorder
<script setup lang="ts">
const tasks = ref([{ id: 'draft' }, { id: 'review' }, { id: 'ship' }])
async function persistOrder({ items }: { items: Array<{ id: string }> }) {
tasks.value = items
await api.saveTaskOrder(items.map(item => item.id))
}
</script>
<template>
<TxSortableList v-model="tasks" @reorder="persistOrder" />
</template>
Best Practices
- Use stable persisted ids, never array indexes.
- Update the local array with
v-model; persist fromreorderwhen server order matters. - Turn on
handlefor rows with buttons, links, inputs, or selectable text, and for long touch lists so rows don't capture swipes. - Pass
itemLabelwhen ids aren't human-readable, or screen readers announce ids likeplugin-a1b3. - Keep lists modest; for very long ones, pair a different drag strategy with virtualization.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | SortableListItem[] | required | Ordered list data; every item needs a stable string id. |
disabled | boolean | false | Disables dragging, keyboard reordering, and reorder emits. |
handle | boolean | false | Requires a drag to start from [data-tx-sort-handle="true"]. |
dragMode | 'pointer' | 'native' | 'pointer' | pointer carries the row as others step aside; native uses HTML5 drag and drop, letting items leave. |
ariaLabel | string | - | Accessible name of the list. |
itemLabel | (item) => string | - | Item name in announcements; defaults to the id. |
labels | SortableListLabels | - | Templates for grabbed, moved, dropped, cancelled, and the built-in handle, with {item}, {position}, {size}. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | SortableListItem[] | Once on release for pointer drags; on every step for native drags and the keyboard. |
reorder | { from: number, to: number, items: SortableListItem[] } | Once when the interaction ends, with the start and end indexes. |
Slots
| Slot | Props | Description |
|---|---|---|
item | { item, dragging, grabbed, index, handleAttrs } | Custom item renderer, defaulting to the id; spread handleAttrs onto the element that starts a drag. |
SortableListItem
| Field | Type | Description |
|---|---|---|
id | string | Stable identity for keys and drag state; other fields are preserved. |
Overview
- The root is
role="list"and each itemrole="listitem". - The component owns the preview, so rows move whether or not the host writes
modelValueback; reorders emit a shallow copy that keeps item objects. - A pointer drag starts after 4px of travel and swallows the release click; inputs and editable regions never start one; Escape or
pointercancelcancels without emitting. - A native drag reorders as
dragovercrosses rows, and a drop outside the list still counts. - Keyboard: the list is one tab stop. Space or Enter picks a row up, arrows move it, and pressing again drops it; Escape restores the order, and blur drops it. A
role="status"region announces each step. - Under reduced motion nothing lifts and springs take no time; the carried row still follows the pointer.
Technologies
- Travel and lift use the separate
translateandscaleproperties so each keeps its own timing;resolveTransitioncompiles the springs to CSSlinear()curves. - Source:
packages/tuffex/packages/components/src/sortable-list/.
查看源码
packages/tuffex/packages/components/src/sortable-list/index.ts