Headless drag-and-drop for Vue 3.
No imposed markup. No hard-coded styles. Just logic.
Documentation Β Β·Β Examples Β Β·Β Changelog
- Composable API β
makeDraggableandmakeDroppableattach to any element via a template ref. No wrapper components, no render props. - Smart helpers β
suggestSort,suggestSwap,suggestCopy,suggestRemovehandle positioning and array manipulation, so you never have to writesplicelogic by hand. - Multi-drag β
makeSelectionArealets users select multiple items and drag them together. All helpers handle multi-drag natively. - Nested zones β trees, Kanban boards, and nested droppables work out of the box. The library automatically resolves the correct target array based on cursor position.
- Full preview control β
DragPreviewexposes a default slot. Wrap it in<Transition>,AnimatePresencefrom motion-v, GSAP, or anything else. Per-item custom previews viarenderoption. - Keyboard navigation β built-in with configurable keys and step size.
- Async drop β return a
PromisefromonDropto pause the operation while waiting for user confirmation. Preview stays visible until resolved. - Auto-scroll β viewport and individual scrollable containers, with configurable threshold and speed.
- Constraints β restrict movement to an axis or keep the preview inside a container boundary.
- Zero dependencies β Vue 3 as the only peer dependency.
- Tree-shakeable β import only what you use.
- Full TypeScript β everything is typed.
npm install @vue-dnd-kit/core
# or
yarn add @vue-dnd-kit/core
# or
pnpm add @vue-dnd-kit/corePeer dependency: Vue ^3.5
<!-- App.vue -->
<script setup lang="ts">
import { ref, useTemplateRef } from 'vue';
import { DnDProvider, makeDroppable } from '@vue-dnd-kit/core';
import SortableItem from './SortableItem.vue';
const items = ref(['One', 'Two', 'Three', 'Four']);
const zoneRef = useTemplateRef<HTMLElement>('zone');
makeDroppable(zoneRef, {
events: {
onDrop(e) {
const r = e.helpers.suggestSort('vertical');
if (r) items.value = r.targetItems as string[];
},
},
}, () => items.value);
</script>
<template>
<DnDProvider>
<div ref="zone" class="list">
<SortableItem
v-for="(item, i) in items"
:key="item"
:index="i"
:items="items"
>
{{ item }}
</SortableItem>
</div>
</DnDProvider>
</template><!-- SortableItem.vue -->
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { makeDraggable } from '@vue-dnd-kit/core';
const props = defineProps<{ index: number; items: string[] }>();
const el = useTemplateRef<HTMLElement>('el');
const { isDragging } = makeDraggable(el, {}, () => [props.index, props.items]);
</script>
<template>
<div ref="el" :style="{ opacity: isDragging ? 0 : 1 }">
<slot />
</div>
</template>| Package | Description |
|---|---|
@vue-dnd-kit/core |
Core library β composables, DnDProvider, DragPreview |
@vue-dnd-kit/utilities |
Extra utility helpers |
Full docs with live examples: zizigy.github.io/vue-dnd-kit
Covers: sorting, swap, copy, multi-drag, trees, Kanban, custom preview, animations, keyboard navigation, async drop, constraints, auto-scroll and more.
Issues and pull requests are welcome. For larger changes, please open an issue first to discuss the approach.