Vue Draggable ES
vuedraggable-es is a Vue.js 3 component that enables drag-and-drop functionality for lists, keeping the view model array synchronized with the HTML. It is built upon and exposes all features of Sortable.js, including touch device support, drag handles, smart auto-scrolling, and inter-list dragging. The current stable version is 4.1.1, and it is actively maintained with frequent bug fixes and feature enhancements, as seen in the recent release history. A key differentiator is its explicit compatibility with Vue 3's `transition-group` component and its focus on being an ES module, making it suitable for modern Vue projects. It also allows making existing UI library components draggable while maintaining full control via events. Its development follows the `vue.draggable.next` project, targeting Vue 3 exclusively.
Common errors
-
[Vue warn]: Failed to resolve component: draggable
cause The `draggable` component was not correctly imported or registered in your Vue application.fixEnsure `import draggable from 'vuedraggable-es'` is present in your script and that `draggable` is registered in your component's `components` option or globally if not using `<script setup>`. -
Property 'item-key' is missing in type '{ ... }' but required in type '{ itemKey: any; }'.cause This TypeScript error indicates that the mandatory `item-key` prop for `vuedraggable-es` in Vue 3 is missing.fixAdd the `item-key` prop to the `<draggable>` component, e.g., `:item-key="'id'"`, pointing to a unique identifier property within your list items. -
Uncaught TypeError: vue.defineComponent is not a function
cause You are attempting to use `vuedraggable-es` (designed for Vue 3) within a Vue 2 project, leading to incompatibility with Vue 3-specific APIs.fixIf your project is Vue 2, you must uninstall `vuedraggable-es` and install the `vuedraggable` package. If your project is Vue 3, ensure your `vue` package version meets the `vuedraggable-es` peer dependency requirements (e.g., `^3.2.31`).
Warnings
- breaking This package, `vuedraggable-es`, is specifically designed for Vue 3 and is incompatible with Vue 2 or earlier versions. Attempting to use it in a Vue 2 project will result in runtime errors related to Vue's internal APIs.
- gotcha When using `vuedraggable-es` with Vue 3, the `item-key` prop is mandatory. This prop is crucial for Vue's reactivity system to track elements efficiently, especially when reordering or using `transition-group`.
- breaking The usage of `transition-group` with `vuedraggable-es` requires a specific structure. The `transition-group` component should be effectively 'aliased' by passing `tag="transition-group"` to the `draggable` component, and then the list items are rendered via the `#item` slot.
- gotcha The `vuedraggable-es` package is an ES module (ESM) and is not intended for direct use with CommonJS `require()` statements or in environments that do not support ESM. This is reflected in its package name suffix `-es`.
Install
-
npm install vuedraggable-es -
yarn add vuedraggable-es -
pnpm add vuedraggable-es
Imports
- draggable
const draggable = require('vuedraggable-es')import draggable from 'vuedraggable-es'
- DraggableComponent
import type { DraggableComponent, DraggableEvents } from 'vuedraggable-es' - VueDraggable (UMD)
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/4.0.0/vuedraggable.umd.min.js"></script>
Quickstart
<script setup>
import draggable from 'vuedraggable-es'
import { ref } from 'vue'
const myArray = ref([
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
]);
const drag = ref(false);
function handleStart() {
drag.value = true;
console.log('Drag started');
}
function handleEnd() {
drag.value = false;
console.log('Drag ended', myArray.value);
}
</script>
<template>
<div style="font-family: sans-serif; padding: 20px;">
<h2>Draggable List</h2>
<p>Drag status: {{ drag ? 'Dragging' : 'Not dragging' }}</p>
<draggable
v-model="myArray"
group="people"
@start="handleStart"
@end="handleEnd"
item-key="id"
style="border: 1px solid #ccc; padding: 10px; min-height: 50px;"
>
<template #item="{ element }">
<div style="background: #f9f9f9; border: 1px solid #eee; margin-bottom: 5px; padding: 8px; cursor: grab;">
{{ element.name }}
</div>
</template>
</draggable>
<pre style="background: #eee; padding: 10px; margin-top: 20px;">{{ JSON.stringify(myArray, null, 2) }}</pre>
</div>
</template>