Vue Nestable
raw JSON →vue-nestable is a Vue component designed for creating drag-and-drop hierarchical lists, commonly known as tree views. It allows users to reorder items and intuitively nest them by dragging horizontally. As of version 2.6.0, this package is compatible only with Vue 2 applications. A key differentiator is its deliberate lack of built-in CSS, providing developers with complete control over styling. It offers extensive customization through props for specifying the item identifier (`keyProp`), maximum nesting depth (`maxDepth`), and the horizontal threshold (`threshold`) for nesting actions. The library emphasizes a lightweight and flexible approach, requiring developers to manage their own item data structures and providing components like `VueNestable` for the list and `VueNestableHandle` for draggable areas.
Common errors
error TypeError: Cannot read properties of undefined (reading 'id') ↓
nestableItems array (or whatever data source you're using) have a unique id property, or configure keyProp to match your actual identifier field. error Vue warn]: Invalid prop: type check failed for prop "item". Expected Object, got Undefined. ↓
vue-nestable-handle uses slot-scope="{ item }" (for Vue 2) and v-bind:item="item" or shorthand :item="item" to pass the item object correctly. error Error: The provided id contains invalid characters. ↓
id values of your list items to only include alphanumeric characters, hyphens, and underscores, which are safe for use as CSS class names. Update affected items in your data model. Warnings
breaking This `vue-nestable` package (rhwilr/vue-nestable) is explicitly compatible only with Vue 2. It does not support Vue 3, and there are no current plans for official Vue 3 compatibility from this specific maintainer. For Vue 3, consider alternative packages like `vue3-nestable` (fbki/vue3-nestable or stepanenko3/vue3-nestable) or migrate your application using `@vue/compat` if feasible. ↓
gotcha Each item provided to the `vue-nestable` component via `v-model` or the `value` prop *must* have a unique `id` property (or a custom `keyProp` value). Furthermore, this `id` must be a valid CSS class name, meaning it cannot contain special characters like `:`, `,`, `.`, or `;`. ↓
gotcha The `vue-nestable` component ships without any default styling. While this offers full customization flexibility, developers must provide their own CSS to make the list visually functional and appealing. ↓
gotcha When using `slot-scope` for custom item rendering, ensure the `item` prop is correctly bound to `vue-nestable-handle` and a unique `:key` is provided for each item for optimal Vue reactivity and performance. Omitting the `:key` can lead to unexpected behavior during reordering or nesting. ↓
Install
npm install vue-nestable yarn add vue-nestable pnpm add vue-nestable Imports
- VueNestable (global) wrong
const VueNestable = require('vue-nestable');correctimport VueNestable from 'vue-nestable'; Vue.use(VueNestable); - VueNestable (component) wrong
import VueNestable from 'vue-nestable'; // Incorrect for named export const VueNestable = require('vue-nestable').VueNestable;correctimport { VueNestable } from 'vue-nestable'; - VueNestableHandle wrong
import VueNestableHandle from 'vue-nestable'; // Incorrect for named exportcorrectimport { VueNestableHandle } from 'vue-nestable';
Quickstart
<template>
<div id="app">
<h1>My Nestable List</h1>
<vue-nestable v-model="nestableItems" :maxDepth="3">
<vue-nestable-handle
slot-scope="{ item }"
:item="item"
:key="item.id"
class="nestable-item"
>
{{ item.text }} (ID: {{ item.id }})
</vue-nestable-handle>
</vue-nestable>
<pre>{{ JSON.stringify(nestableItems, null, 2) }}</pre>
</div>
</template>
<script>
import Vue from 'vue';
import { VueNestable, VueNestableHandle } from 'vue-nestable';
Vue.component('VueNestable', VueNestable);
Vue.component('VueNestableHandle', VueNestableHandle);
export default {
name: 'App',
data() {
return {
nestableItems: [
{ id: 0, text: 'Task Alpha' },
{ id: 1, text: 'Task Beta', children: [{ id: 2, text: 'Subtask Gamma' }] },
{ id: 3, text: 'Task Delta' },
{ id: 4, text: 'Task Epsilon', children: [{ id: 5, text: 'Subtask Zeta' }] }
]
};
}
};
</script>
<style>
/* Basic styling for demo purposes */
.nestable-item {
padding: 10px;
margin: 5px 0;
border: 1px solid #ddd;
background: #f9f9f9;
cursor: grab;
}
.nestable-item:active {
cursor: grabbing;
}
</style>