Docs/API
Sensors
What turns input into drags — the built-in pointer and keyboard sensors, and the API to write your own.
import { defineSensor, useSensor, pointerSensor, keyboardSensor } from '@vue-dnd-kit/core';
SensorMouse, touch and pen via Pointer Events. In sensors by default.
SensorSpace/Enter, arrows and Escape (rebound with the provider's keyboard option). In sensors by default; it also cancels pointer and custom drags with Escape, even with keyboard: false.
(sensor: Sensor) => SensorDefines a sensor (see Sensor): it only helps with the types and returns its argument.
(sensor: Sensor) => voidRuns a sensor in the provider above for as long as the calling component (or effect scope) lives, next to the provider's sensors. Its drag is cancelled when it unmounts.
A sensor only says "drag this item from here", then where it moved and that it dropped or was cancelled; the provider checks the rest (what may be dragged, activation, one drag at a time). See Sensors and programmatic drags.
Below, a small custom sensor (run with useSensor) drags the board's pieces from its minimap, next to the provider's own sensors.
Loading the demo…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import SensorDesk from './SensorDesk.vue';
</script>
<template>
<DnDProvider>
<SensorDesk />
</DnDProvider>
</template>Sensor
Input that starts drags: pointer, keyboard, or your own (a gamepad, an on-screen joystick, voice, scripted drags). setup runs once per provider, in the browser only, inside an effect scope that ends with the provider (or when the sensor leaves sensors, or the component that called useSensor unmounts). Register listeners with useEventListener or return a cleanup; a drag still running then is cancelled.
To wrap a sensor, run its setup with a context of your own. Object.create(context, { activate: { value: … } }) keeps the live getters (status, drag, props): a spread would freeze them.
What a sensor gets from the provider it runs in.
Readonly<DnDProviderProps>The provider's props (e.g. activation, keyboard). Read them when needed: they may change.
DnDStatusThe provider's drag status, whichever sensor runs the drag.
SensorDrag | nullThe provider's drag, pending or dragging, whichever sensor started it; null when there is none. Sensors may drive each other's drags: the keyboard sensor moves and drops every keyboard drag, e.g. one a "Move" button picked up (@vue-dnd-kit/actions).
(activation: SensorActivation) => SensorDrag | nullAsks to drag an item. The provider checks that it is idle (one drag at a time, none while a drop lands), that the target is a draggable of its own that isn't disabled, where the input landed (see target) and the draggable's canDrag, then waits for the activation constraint and starts the drag. Returns the drag (pending, or already dragging when there is nothing to wait for), or null when no drag may start.
() => voidCancels the provider's drag or pending activation, whichever sensor runs it (Escape, a hidden tab).
Activation
What a sensor asks for when its input wants to drag (SensorContext.activate()).
Element | KeyWhere the input landed: an element inside a draggable, or the id of a draggable. An element must belong to this provider; for 'pointer' drags it must be on the handle when there is one and not on an interactive child (a button, an input), for 'keyboard' drags it must be the draggable's focus target (the handle, else the draggable itself) and not an editable field. An id skips these checks: the drag starts from the item wherever the input was.
SensorTypeHow the drag moves. 'pointer' (default): it follows the points given to move(), targets are hit-tested there, containers auto-scroll at their edges and the page shows the grabbing cursor. 'keyboard': it moves by items with step() and place() as arrow keys do, targets are revealed instead of auto-scrolled, and the focus goes back to the item when it ends. Active.sensor tells which.
CoordinatesWhere the drag starts, in viewport coordinates. Default: the center of the draggable.
PointerEvent | KeyboardEventThe input event. It is handed to the draggable's canDrag: without one (a gamepad, a programmatic drag), canDrag isn't asked. A pointerType of 'touch' makes the drag a touch drag (haptics).
PointerKind | ActivationConstraintWhat the drag waits for before it starts (useDnD().status is 'activating' until then, with its progress). A pointer kind reads the draggable's activation option for it, then the provider's, then the defaults (mouse 4px, at once on a handle; pen 4px; touch a 200ms long press with 5px tolerance). A constraint is used as it is. Default: none, the drag starts at once.
(drag: SensorDrag) => voidThe drag started, after its activation: e.g. capture the pointer.
(drag: SensorDrag) => voidThe drag is over: its activation was aborted, or it dropped or was cancelled (by anyone).
(drag: SensorDrag) => voidThe drop the sensor asked for didn't happen and the drag goes on (onBeforeDrop answered 'continue'): move, drop and cancel apply again. A pointer sensor lets the item follow the pointer until the next release.
Per pointer kind. Defaults: mouse { distance: 4 } (immediate on a handle), pen { distance: 4 }, touch { delay: 200, tolerance: 5 }.
type ActivationOptions = Partial< Record<PointerKind, ActivationConstraint> >What a press must do before it becomes a drag: travel distance, or be held for delay, whichever comes first. Nothing set: the drag starts at once.
The drag
One drag of a sensor, from activate() until it ends. Every call is ignored once it no longer applies: moves before the start or after the end, a second drop().
KeyId of the dragged item.
SensorTypeHow the drag moves, as activate() asked (SensorActivation.type).
SensorDragStateWhere the drag is: waiting for its activation, dragging, or ended.
booleanThe drag started, even if it has ended since (the pointer sensor swallows the click that follows it).
(point: Coordinates) => voidThe input moved. While pending, the activation constraint is checked (moving past its tolerance aborts it); while dragging, the drag goes there. Pointer drags take one position per frame; keyboard drags move at once, after the steps before them.
(direction: SensorDirection, options?: SensorStepOptions) => Promise<void>Keyboard drags: one arrow step, as the keyboard sensor's arrow keys do (the next item of a list, the next accepting target in 'droppables' mode, or keyboard.step pixels). Steps queue: each runs once the one before has rendered, and a repeated key (event.repeat) is skipped while one still resolves. Pointer drags ignore it.
(position: SortablePosition) => Promise<boolean>Puts the item at a position of a sortable list, as keyboard moves do (other lists take it only if they accept it), and moves the drag to its new place. Resolves false when no list takes it there. Queued like step() in keyboard drags.
() => Promise<boolean>Drops: a pending activation is aborted instead. Resolves once the drag has ended and landed: true when the drop went through, false when it was refused (a target, onBeforeDrop) or there was nothing to drop.
() => voidCancels the drag (it flies back), or aborts a pending activation.
'pending': waiting for the activation constraint;'dragging': from the start until the drop is decided or the drag is cancelled;'ended': the activation was aborted, or the drag dropped or was cancelled, by the sensor or by anything else (Escape, a hidden tab,useDnD().cancel(), the provider unmounting).
type SensorDragState = 'pending' | 'dragging' | 'ended'Options of SensorDrag.step().
Arrow of a keyboard step.
type SensorDirection = 'up' | 'down' | 'left' | 'right'A position in a sortable list, for SensorDrag.place() (and moveItem of @vue-dnd-kit/actions). Lists only: trees place items by their own keys.