Vue Dndrop

1.3.4 · active · verified Sun Apr 19

vue-dndrop is a JavaScript library providing intuitive Vue wrappers for implementing robust drag and drop functionalities within web applications. Currently at stable version 1.3.4, it offers features for reordering elements, transferring items between multiple containers, and defining custom drop rules. The library maintains a moderate release cadence, with a focus on stability and addressing common user experience issues. A key differentiator is its streamlined support for Vue 3.x, which was introduced and stabilized from versions 1.1.0/1.1.1 onwards (initially via an `@next` npm tag). This ensures seamless integration for modern Vue projects. It actively resolves challenges such as scroll blocking on touch devices during dragging and prevents errors from null container states, contributing to a more reliable and polished user experience compared to some alternative solutions.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates a basic draggable list using `vue-dndrop`'s `Container` and `Draggable` components within a Vue 3 Composition API setup. This example allows items to be reordered within a single list and logs any items successfully dropped into it, showcasing the core `onDrop` and `getChildPayload` event handlers.

<template>
  <div class="dnd-example">
    <h2>My Draggable List</h2>
    <Container @drop="onDrop" :get-child-payload="getChildPayload" group-name="items-group" class="smooth-dnd-container">
      <Draggable v-for="item in items" :key="item.id">
        <div class="draggable-item">
          {{ item.text }}
        </div>
      </Draggable>
    </Container>

    <h3>Dropped Items (for demonstration)</h3>
    <pre>{{ JSON.stringify(droppedItems, null, 2) }}</pre>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Container, Draggable } from 'vue-dndrop';

interface Item {
  id: number;
  text: string;
}

const items = ref<Item[]>([
  { id: 1, text: 'Item 1' },
  { id: 2, text: 'Item 2' },
  { id: 3, text: 'Item 3' }
]);

const droppedItems = ref<Item[]>([]);

const onDrop = (dropResult: { addedIndex: number | null; removedIndex: number | null; payload: Item }) => {
  const { addedIndex, removedIndex, payload } = dropResult;

  if (removedIndex !== null && addedIndex !== null) {
    // Reordering within the same container
    const [removed] = items.value.splice(removedIndex, 1);
    items.value.splice(addedIndex, 0, removed);
  } else if (addedIndex !== null && payload) {
    // Item was dropped into this container (e.g., from another list or a new item)
    const newItems = [...items.value];
    newItems.splice(addedIndex, 0, payload);
    items.value = newItems;
    droppedItems.value.push(payload); // Log dropped item for demo
  }
};

const getChildPayload = (index: number): Item => {
  return items.value[index];
};
</script>

<style scoped>
.dnd-example {
  font-family: Arial, sans-serif;
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
  border: 1px solid #eee;
  border-radius: 8px;
  background-color: #fff;
}
h2, h3 {
  text-align: center;
  margin-bottom: 20px;
  color: #333;
}
.draggable-item {
  padding: 15px;
  margin-bottom: 10px;
  background-color: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: grab;
  box-shadow: 0 2px 4px rgba(0,0,0,0.05);
  transition: background-color 0.2s ease;
}
.draggable-item:hover {
  background-color: #f0f0f0;
}
.smooth-dnd-container {
  min-height: 50px;
  background-color: #eef;
  padding: 10px;
  border-radius: 4px;
  margin-bottom: 20px;
  border: 1px dashed #ccc;
}
</style>

view raw JSON →