{"id":12639,"library":"vuedraggable","title":"Vue Draggable for Vue 2.x (Sortable.js Wrapper)","description":"vuedraggable is a Vue 2.x component that provides drag-and-drop functionality for lists, leveraging the robust capabilities of Sortable.js. Version 2.24.3, published over five years ago, is specifically tailored for Vue 2 applications, offering declarative list reordering, multi-drag, and nested list support. It acts as a lightweight wrapper around Sortable.js, abstracting away direct DOM manipulation and integrating seamlessly with Vue's reactivity system. While newer versions (v4.x) exist for Vue 3, this entry focuses on the 2.x branch, which received consistent maintenance and updates for features like TypeScript definitions (since 2.24.0) and SSR compatibility fixes (like in 2.23.2). Its key differentiator remains the powerful and flexible drag-and-drop mechanics inherited from Sortable.js, presented in a Vue-idiomatic way, making it a widely adopted solution for interactive list management in legacy Vue 2 projects.","status":"maintenance","version":"2.24.3","language":"javascript","source_language":"en","source_url":"https://github.com/SortableJS/Vue.Draggable","tags":["javascript","vue","vuejs","drag","and","drop","list","Sortable.js","component","typescript"],"install":[{"cmd":"npm install vuedraggable","lang":"bash","label":"npm"},{"cmd":"yarn add vuedraggable","lang":"bash","label":"yarn"},{"cmd":"pnpm add vuedraggable","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core drag-and-drop logic; vuedraggable is a wrapper around Sortable.js.","package":"sortablejs","optional":false},{"reason":"Peer dependency for Vue 2.x applications.","package":"vue","optional":false}],"imports":[{"note":"For Vue 2.x, `draggable` is typically a default export. It can then be registered locally or globally in your Vue component or app.","wrong":"import { draggable } from 'vuedraggable'; // Not a named export usually\nconst draggable = require('vuedraggable'); // CommonJS for browser/old Node setups","symbol":"draggable","correct":"import draggable from 'vuedraggable';"},{"note":"After importing, `draggable` must be registered as a component for use in templates.","symbol":"Draggable Component Registration","correct":"// In a Vue component:\nexport default {\n  components: {\n    draggable,\n  },\n  // ...\n}"},{"note":"While vuedraggable ships with its own types (since v2.24.0), specific event types like `SortableEvent` usually come directly from the `sortablejs` package, which often requires `@types/sortablejs` to be installed.","wrong":"import { SortableEvent } from 'vuedraggable'; // Types often reside in 'sortablejs' or global.","symbol":"SortableEvent (for types)","correct":"import type { SortableEvent } from 'sortablejs';"}],"quickstart":{"code":"import Vue from 'vue';\nimport draggable from 'vuedraggable';\n\nnew Vue({\n  el: '#app',\n  components: {\n    draggable,\n  },\n  data() {\n    return {\n      list1: [\n        { id: 1, name: 'Item 1' },\n        { id: 2, name: 'Item 2' },\n        { id: 3, name: 'Item 3' },\n      ],\n      list2: [\n        { id: 4, name: 'Item 4' },\n        { id: 5, name: 'Item 5' },\n      ],\n      drag: false,\n    };\n  },\n  methods: {\n    log(evt) {\n      console.log('Drag event:', evt);\n    },\n  },\n  template: `\n    <div id=\"app\">\n      <h2>List 1</h2>\n      <draggable\n        class=\"list-group\"\n        tag=\"ul\"\n        v-model=\"list1\"\n        group=\"items\"\n        @start=\"drag = true\"\n        @end=\"drag = false\"\n        @change=\"log\"\n      >\n        <li\n          class=\"list-group-item\"\n          v-for=\"element in list1\"\n          :key=\"element.id\"\n        >\n          {{ element.name }}\n        </li>\n      </draggable>\n      \n      <h2>List 2</h2>\n      <draggable\n        class=\"list-group\"\n        tag=\"ul\"\n        v-model=\"list2\"\n        group=\"items\"\n        @start=\"drag = true\"\n        @end=\"drag = false\"\n        @change=\"log\"\n      >\n        <li\n          class=\"list-group-item\"\n          v-for=\"element in list2\"\n          :key=\"element.id\"\n        >\n          {{ element.name }}\n        </li>\n      </draggable>\n      <p>Dragging: {{ drag }}</p>\n\n      <style>\n        .list-group { min-height: 50px; border: 1px solid #eee; padding: 10px; margin-bottom: 20px; }\n        .list-group-item { padding: 10px; margin-bottom: 5px; background-color: #f9f9f9; border: 1px solid #ddd; cursor: grab; }\n        .list-group-item:active { cursor: grabbing; }\n      </style>\n    </div>\n  `,\n});","lang":"javascript","description":"This example demonstrates basic usage of `vuedraggable` (v2.x) to create two interconnected sortable lists in a Vue 2 application. It uses `v-model` for data synchronization, `group` for drag-and-drop between lists, and logs `start`, `end`, and `change` events to the console."},"warnings":[{"fix":"For Vue 3 projects, install `vuedraggable@next` or `vue-draggable-next` (e.g., `npm i vuedraggable@next` or `yarn add vuedraggable@next`). For Vue 2 projects, ensure you are using a `vuedraggable` v2.x version.","message":"Version 2.x of `vuedraggable` is designed exclusively for Vue 2.x applications. Attempting to use it directly in a Vue 3 project will result in runtime errors due to fundamental API changes in Vue 3. For Vue 3, `vuedraggable@next` or `vue-draggable-next` (v4.x) is required.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Always use a unique and stable identifier for the `:key` prop on elements rendered inside `vuedraggable`'s slot, such as an item's `id` property (e.g., `:key=\"element.id\"`).","message":"Children elements within `vuedraggable`'s `v-for` loop must always have unique `:key` bindings. Using array indices (`:key=\"index\"`) is explicitly discouraged, especially when items can be added, removed, or reordered, as it can lead to rendering issues, incorrect state updates, or duplicate elements. Keys should be stable and linked to the item's content.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Install the Sortable.js type definitions: `npm install --save-dev @types/sortablejs`. Then, import types as needed, e.g., `import type { SortableEvent } from 'sortablejs';`.","message":"When working with TypeScript, while `vuedraggable` v2.24.0+ ships with basic component definitions, specific event types (like those emitted by Sortable.js) may require installing `@types/sortablejs` to get full type safety for event payloads, such as `SortableEvent`.","severity":"gotcha","affected_versions":">=2.24.0"},{"fix":"Upgrade to `vuedraggable` v2.19.0 or higher. If upgrading isn't an option, continue using the `:options` prop to pass Sortable.js configuration. For newer versions, prefer direct props (e.g., `group=\"items\"`, `animation=\"150\"`) but avoid 'on'-prefixed methods as props, as these are handled by `vuedraggable` events.","message":"Older versions of `vuedraggable` (pre-2.19.0) required passing Sortable.js options via a `:options` prop (e.g., `:options=\"{ group: 'name' }\"`). Since v2.19.0, most Sortable.js options can be passed directly as `vuedraggable` props using kebab-case.","severity":"deprecated","affected_versions":"<2.19.0"},{"fix":"Consider adding a specific 'handle' element to your draggable items (e.g., `<span class=\"handle\">:::</span>`). Then, configure `vuedraggable` with the `handle` prop: `:handle=\".handle\"`. This ensures only interaction with the handle triggers dragging. Also, ensure `touch-action: none;` is not preventing touch events on touch devices.","message":"If drag-and-drop functionality appears to be non-responsive, especially with input fields or text selection, it might be due to a conflict with default browser drag behavior or a lack of a defined drag handle.","severity":"gotcha","affected_versions":">=2.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `draggable` is included in the `components` option of your Vue component (e.g., `components: { draggable }`) or registered globally with `Vue.component('draggable', draggable);`.","cause":"The `draggable` component was imported but not properly registered with Vue.","error":"[Vue warn]: Unknown custom element: <draggable> - did you register the component correctly?"},{"fix":"Ensure the data bound to `v-model` (or `list`) is a reactive array. If using Vuex, you might need to use the `list` prop and handle changes via `splice` in actions/mutations, or use the `clone` prop for complex objects to avoid direct mutation issues.","cause":"The `v-model` or `list` prop passed to `vuedraggable` is not an array, or it's an immutable value that cannot be modified directly.","error":"TypeError: Cannot read property 'map' of undefined (or similar errors related to `v-model` array manipulation)"},{"fix":"Verify that each item in your `v-for` loop inside `<draggable>` has a unique and stable `:key` prop, preferably an `id` from your data, not an array index. Also, ensure you are not accidentally creating new list instances instead of modifying the existing one.","cause":"Often related to incorrect key binding (`:key`) for elements in the `v-for` loop within `vuedraggable`, leading Vue to mismanage element rendering during DOM updates.","error":"Elements visually duplicate or disappear temporarily during drag, but data model is correct after refresh."},{"fix":"Consult `vuedraggable` examples for nesting. When using with tables, `vuedraggable` might need to wrap `<tbody>` or individual `<tr>` elements, often requiring `tag=\"tbody\"` or `tag=\"tr\"` on the draggable component. For `v-data-table`, ensure `draggable` is correctly placed within its slots, like `tbody`, and adjust the `tag` prop accordingly.","cause":"Structural conflicts with parent components (like `<table>` or `v-data-table` in Vuetify) or incorrect placement of `draggable` and its child elements, potentially breaking HTML table structure.","error":"Drag-and-drop functionality does not work when `vuedraggable` is nested or within complex layouts (e.g., data tables)."}],"ecosystem":"npm"}