Skip to content

Events

Callbacks in the options object everywhere; additionally emitted as component events in Vue (@end) and as DOM CustomEvents on <dnd-list> (dnd-end).

Because the model updates live during the drag (that's what moves the items on screen), the granular events also fire live — not just on drop. onEnd is the "commit" signal.

CallbackVue event<dnd-list> eventFires
onStartstartdnd-startThe pointer crossed the threshold — drag is live.
onEndenddnd-endDrag finished (dropped, cancelled or spilled).
onMovemoveThe dragged block moved to a new list/index.
onAddadddnd-addThis list gained an item (cross-list or clone).
onRemoveremovednd-removeThis list lost an item.
onUpdateupdatednd-updateAn item was reordered within this list.
onChangechangednd-changeUnion event — one of added/removed/moved.
onChoosechoosednd-choosePointer went down on an item.
onUnchooseunchoosednd-unchoosePointer released (drag or not).
onSelectionChangeselection-changednd-selectMulti-drag selection changed.
onKeyboardMovekeyboard-movednd-keyboardA keyboard reorder was committed.
onKeyboardStateChange— (internal)The keyboard-held index changed (number | null).

Payloads

ts
interface DragStartEvent<T> {
  item: T
  index: number
  fromList: readonly T[]
  fromEl: HTMLElement
  originalEvent: PointerEvent
}

interface DragEndEvent<T> {
  item: T
  oldIndex: number
  newIndex: number            // -1 when cancelled/spilled
  fromList: readonly T[]
  toList: readonly T[]
  fromEl: HTMLElement
  toEl: HTMLElement
  pullMode: false | true | 'clone'
  cancelled: boolean
  originalEvent: PointerEvent | KeyboardEvent
}

interface DragMoveEvent<T> {
  item: T
  fromList: readonly T[]
  toList: readonly T[]
  fromEl: HTMLElement
  toEl: HTMLElement
  oldIndex: number
  newIndex: number
  willInsertAfter: boolean
  originalEvent: PointerEvent
}

interface AddEvent<T>    { item: T; newIndex: number }
interface RemoveEvent<T> { item: T; oldIndex: number }
interface UpdateEvent<T> { item: T; oldIndex: number; newIndex: number }

interface ChangePayload<T> {
  added?:   { item: T; newIndex: number }
  removed?: { item: T; oldIndex: number }
  moved?:   { item: T; oldIndex: number; newIndex: number }
}

interface ChooseEvent<T>          { item: T; index: number }
interface SelectionChangeEvent<T> { items: T[]; indices: number[] }
interface KeyboardMoveEvent<T>    { item: T; oldIndex: number; newIndex: number }

Patterns

Persist on drop only:

ts
onEnd: ({ cancelled }) => {
  if (!cancelled) saveOrder(items)
}

Track cross-list transfers:

ts
// On the receiving list:
onAdd: ({ item, newIndex }) => api.assign(item.id, laneId, newIndex)
// On the giving list:
onRemove: ({ item }) => api.unassign(item.id, laneId)

Escape / spill detection: onEnd fires with cancelled: true for Escape, pointercancel and revertOnSpill; removeOnSpill drops arrive with cancelled: false and toEl = the source container.

Released under the MIT License.