vael-ui v0.3.10

Gestures

Sortable

A drag-to-reorder list with a real keyboard path, not just a pointer one.

Install

import { Sortable } from 'vael-ui'

Playground

  • Apple
  • Banana
  • Cherry
  • Date
  • Elderberry
  • Press Space or Enter to start reordering. Use the arrow keys to move, Space to drop, Escape to cancel.
import { Sortable } from 'vael-ui'

<Sortable axis="y" autoScroll :disabled="false" motionCss previewMode="element" :touchDragDelay="0" :items="items">Sortable</Sortable>

Props

NameTypeDefaultDescription
itemKeykeyof T | undefined"value" as neverProperty holding each item's stable identity. Defaults to `value`, the same item vocabulary `MenuItemData`/`SelectItemData`/`TreeNode` already use.
labelKeykeyof T | undefined"label" as neverProperty to announce and to render when no `#item` slot is given.
axis"y" | "x""y"`'y'` (default) reorders a column of rows; `'x'` reorders a row of items. Arrow keys follow the axis.
canDrop((details: SortableDropDetails) => boolean) | undefinedundefinedStructural veto, re-run while dragging: `false` marks the target invalid. Keep it cheap.
beforeDrop((details: SortableDropDetails) => boolean | Promise<boolean>) | undefinedundefinedAsync gate at drop time. Return `false` (or a promise of it) to cancel — composes with `confirmAction().result`.
autoScrollboolean | undefinedtrueScrolls the list, any scrollable ancestor, or the page while a drag nears its edge. Default `true`.
disabledboolean | undefinedfalseTurns off dragging; rows become static.
motionCssboolean | undefinedtrue`false` skips the built-in springs entirely — rows snap to their new slots. Reach for it when driving the motion yourself.
groupSortableGroupHandle | undefinedundefinedShares drag sessions with other `<Sortable>`s/`useSortable()` lists passed the same handle — from `useSortableGroup()`. Lets an item cross between them.
groupIdstring | number | undefinedundefinedThis list's identity within `group`. Auto-assigned if omitted.
previewMode"element" | "clone"`group` only — how a drag looks once it leaves this list for a sibling one. `'element'` (default): the real dragged item lifts and keeps moving, so there's only ever one instance of it on screen. `'clone'`: a separate floating copy, for content that can't tolerate leaving its normal layout.
touchDragDelaynumber | undefinedMs a touch pointer must hold a row still before a drag starts. Skip this unless `#item`/`#handle` content is also tappable for something else — the built-in handle alone never needs it. Default `0`.
uiPartial<{ root: UiPartValue; item: UiPartValue; handle: UiPartValue; }> | undefinedundefined
itemsT[] | undefined[]The list, in order. Reassigned to a new array on a committed drop — bind with `v-model:items`.

Slots

NameTypeDescription
item{ item: T; index: number; grabbed: boolean; }Row content. Falls back to `labelKey`'s value when omitted.
handle{ item: T; }Replaces the default drag handle.

Events

NameTypeDescription
drop-error[error: unknown, details: SortableDropDetails]
reorder[value: string | number, to: DropPosition]
update:items[value: T[]]

Exposed

NameTypeDescription
elunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
isGrabbedunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
isValidDropunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
isPendingunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
isForeignDropTargetunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
activeValueunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.