Vize

Sortable

Headless Sortable; covers React Aria useDraggableCollection, ARIA APG drag reordering.

Package @vizejs/ui/sortable
Maturity stable
Own the source vize lib pull sortable
Requires drag-and-drop
Aliases sortable list, reorder, sortable grid, sortable tree
Covers React Aria useDraggableCollection, ARIA APG drag reordering

API

createSortable

Create an SSR-safe sortable coordinator for lists, grids, and trees.

function createSortable(options: SortableOptions = {}): SortableController

useSortable

Create a sortable coordinator disposed with the current Vue effect scope.

function useSortable(options: SortableOptions = {}): SortableController

readOrientation

Resolve the closed orientation union without accepting mistyped JavaScript.

function readOrientation(value: SortableOptions["orientation"]): SortableOrientation

readDirection

Resolve the closed direction union without accepting mistyped JavaScript.

function readDirection(value: SortableOptions["direction"]): SortableDirection

readColumns

Resolve a positive integer column count for grid arrow-key geometry.

function readColumns(value: SortableOptions["columns"]): number

edgesFor

Drop edges one item target resolves for an orientation.

function edgesFor(orientation: SortableOrientation, nesting: boolean): readonly DropEdge[]

edgeForPosition

Map a logical position back onto the physical edge for an orientation.

function edgeForPosition( position: SortablePosition, orientation: SortableOrientation, direction: SortableDirection, ): DropEdge

createSortableEvent

Build a frozen lifecycle snapshot for sortable callbacks.

function createSortableEvent<Type extends SortableEventType>( type: Type, pointerType: DragPointerType, key: string, fromIndex: number, toIndex: number, overKey: string | null, position: SortablePosition | null, originalEvent: Event | null, ): SortableEvent<Type>

positionForEdge

Map a physical drop edge onto the logical position for an orientation.

function positionForEdge( edge: DropEdge, orientation: SortableOrientation, direction: SortableDirection, ): SortablePosition

computeToIndex

Compute the insertion index for moving fromIndex relative to overIndex. "inside" moves report the receiving item's index unchanged.

function computeToIndex( fromIndex: number, overIndex: number, position: SortablePosition, ): number

keyboardDelta

Signed index step for one arrow key, or null when the key is not owned.

function keyboardDelta( key: string, orientation: SortableOrientation, direction: SortableDirection, columns: number, ): number | null

dispatchSortableEvent

Dispatch one lifecycle snapshot to the matching consumer callback.

function dispatchSortableEvent(options: SortableOptions, event: SortableEvent): void

projectDragContext

Project a drag-and-drop context onto sortable indexes and positions.

function projectDragContext( keys: readonly string[], orientation: SortableOrientation, direction: SortableDirection, dragContext: DragContextSlice, ): SortableProjection

sortableContextFor

Build the sortable announcement context for one drag announcement phase.

function sortableContextFor( phase: "cancel" | "drop" | "grab" | "move", dragContext: AnnouncementSlice, projection: SortableProjection, count: number, originIndex: number | null, ): SortableAnnouncementContext

defaultSortableAnnouncements

Built-in English announcement builders; consumers override to localize.

const defaultSortableAnnouncements: Required<SortableAnnouncements>

handleSortableKeydown

Handle one keydown from an item: grab, move, nest, drop, or cancel.

function handleSortableKeydown( host: SortableKeyboardHost, event: KeyboardEvent, key: string, ): void

cancelSortableKeyboard

Cancel an owned keyboard sort from focus loss or programmatic teardown.

function cancelSortableKeyboard(host: SortableKeyboardHost, event: Event | null): boolean

Behavior

Normative state × input → outcome table for @vizejs/ui/sortable. Every row is exercised by src/families/interaction/sortable/sortable*.test.ts; compile-only assertions live in src/families/interaction/sortable/sortable.types.test-d.ts.

# State Input Outcome Proven by
S1 idle items register in any order logical indexes follow document order, not registration order ordering test
S2 idle pointer travels the start distance on an item sortstart reports the item's current index and announces the grab pointer lifecycle test
S3 sorting pointer over another item's leading half preview projects before and the indicator carries the edge line pointer preview test
S4 sorting pointer over another item's trailing half preview projects after with the moved insertion index pointer preview test
S5 sorting unchanged projection on further movement no duplicate preview is emitted preview dedup test
S6 sorting over an item owning contact releases sortcommit reports origin and final indexes exactly once pointer commit test
S7 sorting Escape, blur, hidden document, or cancel() sortcancel reports the index to return to and announces the return cancellation tests
S8 sorting released outside owning contact releases over no item the sort cancels back to the origin index outside-release test
S9 idle focus on item Enter or Space without modifiers keyboard sort grabs, reports position, and speaks usage instructions keyboard grab test
S10 keyboard sorting (vertical) ArrowUp and ArrowDown, Home, and End destination steps and clamps; each change previews and announces keyboard move tests
S11 keyboard sorting (grid) ArrowUp and ArrowDown destination steps by the resolved column count grid keyboard test
S12 keyboard sorting (horizontal, RTL) ArrowLeft and ArrowRight logical direction flips with the resolved writing direction RTL keyboard test
S13 keyboard sorting (nesting) ArrowRight then ArrowLeft preview nests inside the previous item, then returns to index moves nesting keyboard test
S14 sorting (nesting) pointer inside an item's central band preview and commit report "inside" with the receiving item's key nesting pointer test
S15 keyboard sorting Enter or Space sortcommit reports origin and destination and announces the drop keyboard commit test
S16 disabled item or controller any grab attempt no sort starts; an active sort cancels on reactive disablement disablement tests
S17 any sort item registration disposal the owning sort cancels first and both registrations release disposal tests
S18 any sort controller disposal delegated listeners and reactive state release without callbacks disposal tests
S19 concurrent SSR requests identical component trees byte-identical markup contains no handlers or DOM reads SSR test
S20 SSR followed by hydration keyboard sort host identity remains and reactive output updates without warning hydration test
S21 public TypeScript API mutation or invalid closed union compilation rejects misuse type assertions

Accessibility and layout obligations

Every item host must be keyboard focusable so pointer sorting has an Enter-grab, arrow-move, Enter-drop equivalent, and every phase speaks through the underlying drag-and-drop live region with injectable, localizable builders. Grid and horizontal arrow keys resolve against the configured writing direction so RTL layouts move logically. The primitive is headless: it assigns no role or style, and consumers render placeholder and indicator geometry from the reactive indicator state. Nested trees compose this family with the drag-and-drop core's innermost-target ownership; "inside" previews and commits carry the receiving item so consumers re-parent their own model.