Docs/API
makeSortableList
Makes a container a sortable list — a draft that reorders while you drag, written back on drop.
function makeSortableList<T>( target: MaybeElementRef, options: SortableListOptions<T>,): SortableListReturn<T>;Makes a container a sortable list. Render the returned items (the draft order), not your array: the drop is written back to options.items, after onDrop, unless event.preventDefault() leaves event.result to you.
const list = useTemplateRef<HTMLElement>('list');
const { items } = makeSortableList(list, { items: tasks, group: 'board' });
Its rows call makeSortableItem. See
Sortable lists and Lists that share items.
Loading the demo…
<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider } from '@vue-dnd-kit/core';
import Segmented from './Segmented.vue';
import Tiles from './Tiles.vue';
const strategy = ref<'vertical' | 'horizontal' | 'grid'>('grid');
const placeholder = ref<'item' | 'indicator'>('item');
const behavior = ref<'sort' | 'swap'>('sort');
</script>
<template>
<DnDProvider>
<div class="demo">
<div class="switches">
<Segmented v-model="strategy" name="strategy" :options="['vertical', 'horizontal', 'grid']" />
<Segmented v-model="placeholder" name="placeholder" :options="['item', 'indicator']" />
<Segmented v-model="behavior" name="behavior" :options="['sort', 'swap']" />
</div>
<code class="call">makeSortableList(el, { strategy: '{{ strategy }}', placeholder: '{{ placeholder }}', behavior: '{{ behavior }}' })</code>
<Tiles :strategy="strategy" :placeholder="placeholder" :behavior="behavior" />
</div>
</DnDProvider>
</template>
<style scoped>
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
max-width: 100%;
}
.switches {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16px;
}
.call {
max-width: 100%;
padding: 6px 10px;
overflow-x: auto;
border-radius: 8px;
background: color-mix(in srgb, currentColor 6%, transparent);
font: 11px/1.4 ui-monospace, Menlo, Consolas, monospace;
white-space: nowrap;
color: #42b883;
}
</style>Options
Options of makeSortableList. A component may make several lists (and trees): each item rendered in it joins the innermost one whose element holds it.
Options take a value, a ref or a getter (overlay, overOverlay, dropAnimation, overDropAnimation, animation: a value or a ref) and are read when the list needs them, so a change applies to the next drag at the latest. Exceptions: id and group are read once, when the list is created; items is the model itself; functions (getKey, filter, clone, createItem, the callbacks) are passed as they are.
SortableItems<T>Source of truth. A writable ref takes the new array on drop, right after onDrop. A read-only source (a getter, a readonly ref, a computed) can't: call event.preventDefault() and apply event.result yourself. Development builds warn about a drop left to the library there, which then changes nothing.
(item: T) => KeyDefault: item.id, or the item itself for primitives. Also keys makeSortableItem({ item }).
(item: T) => booleanShows only the items it returns true for (a search, a tag): items (the returned one) has them, and a drag sorts among them. The others keep their places in the source: a drop writes the whole array, each hidden item still after the shown one it followed (after the nearest that stayed, when that one moved). Reactive: what it reads (a query ref) applies at once. e.to.index and activeIndex count the shown items.
KeyDefault: useId(), stable between server and client render. Read once.
stringvalue · ref · getterWhat people call the list: screen reader texts say it instead of its id (position 2 of 5 in Garden).
unknownvalue · ref · getterAnything to tell about the list as a drop target: events carry it as over.data while a drag is over it.
ActivationOptionsvalue · ref · getterHow a press on this list's items starts a drag, instead of the provider's activation (an item's own wins). Read when a press starts.
Componentvalue · refOverlay component for this list's items (an item's own overlay wins). It receives OverlayProps and stays for the whole drag, also over other lists, unless the target under the drag has an overlay of its own (overOverlay). A ref switched mid-drag swaps it at once.
Componentvalue · refWhat the overlay shows while a drag this list accepts is over it, whatever list it comes from: a component that gets OverlayProps and the drag's own overlay as its default slot (see DroppableOptions.overOverlay). Read live.
DropAnimationvalue · refHow the overlay lands when a drag of this list's items ends, instead of the provider's dropAnimation (an item's own wins; a drop target's wins over both). Read at the drop.
DropAnimationvalue · refHow the overlay lands when it is dropped into this list, whatever list it comes from: wins over the dragged item's and the provider's dropAnimation. Read at the drop.
Modifier[]value · ref · getterModifiers for drags of this list's items, applied after the provider's modifiers (an item's own modifiers win): e.g. [restrictToVerticalAxis] to keep a vertical list's items on their axis. Read when the drag starts.
'x' | 'y'value · ref · getterLocks drags of this list's items to one axis: 'y' for a vertical list, 'x' for a horizontal one (an item's own axis wins). The lock comes after the modifiers, so it holds whatever they do. Read when the drag starts.
string | SortableGroupOptions<T>Lists with the same group name exchange items. Default: a group of its own. Read once.
AcceptModevalue · ref · getterMulti-drag of items of several types: 'all' (default) or 'some' must be accepted (group.put).
SortableStrategyvalue · ref · getterDefault 'vertical'.
SortableBehaviorvalue · ref · getter'swap': the dragged item exchanges places with the hovered one, live; moving back onto it or off the lists reverts. Lists of one group that both swap exchange items between them: the hovered item moves into the dragged one's place, so it must be able to leave its list (group.pull: true) and enter the dragged item's (group.put). Multi-drag sorts instead. Default 'sort'.
SortablePlaceholdervalue · ref · getter'indicator': the list doesn't move, indicator says where the drop goes. Default 'item'.
MultipleModevalue · ref · getterMulti-drag mode of drags that start in this list. Default 'group'. Read when the drag starts.
booleanvalue · ref · getterfalse: items can't be reordered inside this list (palettes).
(item: T) => TCreates copies (pull: 'clone', copy modifier key). Required for copying.
(active: Active) => T | T[]Accepts plain draggables from outside: creates the item to insert. With the keyboard, an arrow toward the list takes the draggable in (level with it, as moves between lists go), and the created item then moves by slots like any other.
A drag from outside the page (external) is asked twice: while it is held, for the item that shows where it goes (only active.external.fileTypes and types are known then), and at the drop, with its data (active.external.ready), for what is inserted. A list of items inserts them all where the slot was: a file each.
ExternalAcceptvalue · ref · getterTakes drags from outside the page: files, links, text (see ExternalAccept). The list makes room for them as for a plain draggable, with createItem, which it needs. Items of its group dragged in from another window of the app (native) need neither option: they come in as themselves. A value, a ref or a getter, read live.
DropOutsidevalue · ref · getterA drop outside every target: keep the items where the placeholder is, cancel, or remove them. Default 'placeholder' ('cancel' with placeholder: 'indicator'). Read at the drop.
LayoutAnimationvalue · refFLIP animation of this list; default: the provider's animation. A value or a ref (a function is a custom animation).
AutoAnimationvalue · ref · getterAnimates changes of items that no drag made: added, removed, moved and filtered items (see AutoAnimation). Default: the provider's animateChanges, off unless set there. Read when items changes.
booleanvalue · ref · getterThe list's own size follows its items: when a drag brings an item in or takes one out (and at the drop, and for the changes animateChanges shows), it grows or shrinks to its new size with animation's duration and easing instead of jumping, and what is around it moves along. Default true; false lets it jump. Read on every change.
boolean | AutoScrollOptionsvalue · ref · getterOverrides the provider's autoScroll for this list's scroll container. Read when the drag starts.
MaybeElementRefThe element that takes drops for the list, default the list element itself: e.g. the whole column around a short list of cards, so a card let go below the last one still lands in the list (at its end). The items stay in the list element.
booleanvalue · ref · gettertrue: its items can't be dragged, and it takes no items.
( event: SortableDropEvent<T>, ) => MaybePromise<BeforeDropResult>Asked before a drop into this list, and before dropOutside: 'remove' takes its items out: false rejects it (the items fly back), some keys accept only those. May be async: the overlay waits where it was dropped. An error rejects the drop too. See SortableDropEvent for result and preventDefault.
(event: SortableDropEvent<T>) => voidCalled once a drop into this list is accepted, before it is written: items still holds the old order, event.result the new one. Synchronous: the write follows as it returns, unless it called event.preventDefault(). Also called on the list the items came from when they are removed (to.index is -1).
Returns
What makeSortableList returns.
KeyThe list's id: the id option, or the one made for it.
ComputedRef<T[]>Draft order: render this, not the source array.
ComputedRef<boolean>A drag is over the list.
ComputedRef<boolean>Something is being dragged and this list takes it.
ComputedRef<SortableIndicator | null>Indicator mode: where the drop goes in this list; null when not here.
ComputedRef<Key | null>The row a virtualizer must keep mounted: the slot while it is in this list (a copy, a created item), otherwise the dragged item; null without a drag.
ComputedRef<number>Index of the active item in this list's draft, -1 when it isn't here.
ComputedRef<Size | null>Size of the dragged item at drag start: e.g. for the size of a virtual row it holds.
() => voidAnimates layout changes the library didn't cause (e.g. a virtualizer re-measure).
Groups
A list's group: the lists that exchange items, and whether items may leave and enter this one.
stringLists and trees with the same name exchange items.
boolean | 'clone'Can items leave this list: move, copy ('clone', a palette) or not at all.
boolean | string | string[] | ((context: SortablePutContext<T>) => boolean)Can items enter this list: true (default), false, a type or types the items must have (as a drop target's accept: with acceptMode, all of them or some), or a function of the drag.
What a function group.put is asked with: the items that would enter the list.
The drop event
What onBeforeDrop and onDrop get.
A drop on a sortable list or tree. Its hooks run in order: onBeforeDrop decides, onDrop is told, then the default action writes result into the items of every list it names, and the overlay lands. preventDefault() in either hook skips that write, so you can apply result yourself.
Key[]Keys of the dragged items.
T[]The items that land: the dragged ones, their copies (mode: 'copy'), or the item createItem made ('insert').
Key[]Keys that go through: all of them, unless the list or onBeforeDrop takes only some.
Key[]Keys that fly back to where they were.
{ list: Key | null; index: number }Where the drag started: the list and index of the active item. list is null for a plain draggable from outside.
{ list: Key; index: number }index is -1 when nothing landed: the items left their lists (e.source.remove(), dropOutside: 'remove').
booleanThe drop stays in the list the drag started from.
DragModeWhat the drop does (see DragMode).
{ key: Key; item: T; from: { list: Key; index: number }; to: { list: Key; index: number } }mode: 'swap': the item the dragged one was exchanged with. It moved the other way, from the place the dragged item took (to above) to the one the dragged item started at (from above); between lists, into the dragged item's list.
ReadonlyMap<Key, T[]>The new items of every list the drop changes, by list id: exactly what the default write puts in their items, as new arrays. Moves, copies, created items, a partial accept, both sides of a swap and items removed (e.source.remove() in a target inside an item, a trash zone, dropOutside: 'remove') are all in it; a list the drop leaves as it is isn't. A tree's entry is a new root array: the nodes on the changed paths are copies (withChildren), untouched subtrees are shared, your nodes are never mutated. In onBeforeDrop it is the drop as it stands before the hook answers (returning some keys changes it); onDrop gets the final one.
() => voidSkips the default write, into every list in result (writing only some would lose or duplicate items). Apply result yourself in onDrop, or before an async onBeforeDrop resolves, and the overlay lands in the new order. Applied nowhere, the lists stay as they were and the overlay flies back (copies and created items, which have no place yet, fade out).
booleanpreventDefault() was called, in onBeforeDrop or onDrop.
ExternalDataA drag from outside the page (external): what it carried, with its data (it was dropped).
Indicator
What indicator holds in placeholder: 'indicator' mode.
Where the drop goes with placeholder: 'indicator': the list doesn't move, you draw the line.
KeyId of the list (or tree) the drop goes into.
numberInsertion position in the list as rendered.
Key | nullItem the indicator is attached to; null in an empty list.
'before' | 'after' | 'inside' | 'swap'Side of key the line goes on. 'inside' (trees): the middle of a row that takes the dragged nodes is hovered, the drop goes into it as its first child. 'swap' (behavior: 'swap'): key is the item the drop exchanges with; mark the item itself.
numberTrees: depth the dropped nodes get (roots are 0), e.g. to indent the line.
Key | nullTrees: parent the dropped nodes get, null at the root level.
Values
A source of sortable items. A writable ref: the library writes each drop into it. A read-only one (a getter, a readonly ref, a computed: an immutable store, server state, a store changed only through actions): you apply each drop from event.result, after event.preventDefault() (see SortableDropEvent).
type SortableItems = Ref<T[]> | Readonly<Ref<readonly T[]>> | (() => readonly T[])How a list lays out its items: a column ('vertical'), a row ('horizontal') or a grid that wraps ('grid').
type SortableStrategy = 'vertical' | 'horizontal' | 'grid'What hovering an item does: 'sort' makes room (the items between shift), 'swap' exchanges the two items.
type SortableBehavior = 'sort' | 'swap'How a drag shows where it goes: 'item', the dragged item's slot moves through the list; 'indicator', the list stays as it is and indicator says where the drop goes (you draw the line).
type SortablePlaceholder = 'item' | 'indicator'What the other selected items do in a multi-drag:
'group': they leave their places and travel with the active item as contiguous placeholders, so while hovering the list already shows the result of the drop;'gaps': they stay in place until the drop;'stack': they collapse into the overlay.
The default overlay shows the dragged items in a column along the list ('group', 'gaps'; a row in horizontal lists, a pile behind the active one in grids), or the active one with a count ('stack').
type MultipleMode = 'group' | 'gaps' | 'stack'What a drop outside every target does: 'placeholder' keeps the items where their slot is, 'cancel' sends them back, 'remove' takes them out of their list.
type DropOutside = 'placeholder' | 'cancel' | 'remove'