@bitboss-dev/vue-dnd
v0.0.2
Published
A lightweight **(4kb)**, performant drag and drop library for Vue 3.
Readme
Vue DnD
A lightweight (4kb), performant drag and drop library for Vue 3.
Features
- 🚀 Vue 3 & Composition API - Built specifically for Vue 3 with script setup syntax
- 📦 TypeScript First - Full TypeScript support with comprehensive type definitions
- 🎯 Namespace-based - Avoid conflicts between separate drag operations. A subject within the
to-do-listnamespace will exclusively interact with events on targets sharing the same namespace. Seamlessly. - 🔄 Deduplicated - Built-in deduplication. Only the topmost element will receive the event but you can change that if you want.
- 🎨 Visual Feedback - Built-in clone dragging with smooth animations
- 🔧 Flexible - Make it as granular as you need.
- 📱 Touch Support - Works on mobile devices with touch events
Installation
npm install @bitboss-dev/vue-dndQuick Start
<template>
<div class="app">
<!-- Draggable Item -->
<div
ref="draggableItem"
class="draggable-item"
:class="{ 'draggable-item--dragging': isDragging }"
>
Drag me!
</div>
<!-- Drop Zone -->
<div
ref="dropZone"
class="drop-zone"
:class="{ 'drag-zone--active': isOver }"
>
Drop here
</div>
</div>
</template>
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import {
useDragSubject,
useDragTarget,
useDragClone,
} from '@bitboss-dev/vue-dnd'
const draggableItem = useTemplateRef('draggableItem')
const dropZone = useTemplateRef('dropZone')
// Set up drag subject (the element to be dragged)
const { isDragging, attributes } = useDragSubject(
draggableItem,
'my-drag-namespace'
)
// Set up drop target
const { isOver } = useDragTarget(dropZone, 'my-drag-namespace')
// Create visual clone during drag
useDragClone(draggableItem, attributes)
</script>Why and how
This library is designed for a straightforward task: dragging an item from point A to point B. Once you release the dragged item, everything resets. You can't continue dragging the item indefinitely; it either reaches the target or resets. This approach addresses the most basic use case.
The API is clear and easy to use.
Steps to get started:
- Define a namespace. For example, if you're dragging a user card into a contact list, use a
user-contactsnamespace. - Create a card to act as the draggable item and apply the composable with the specified namespace.
- Set up a surface as the drop target and apply the composable with the same namespace.
- That's it!
API Reference
useDragAttributes low level helper to track drag events.
Provides reactive drag attributes and a basic flag. Useful for low-level drag tracking or custom drag-and-drop implementations.
function useDragAttributes(
elementRef: MaybeRefOrGetter<unknown>,
options?: DragAttributesOptions
): {
attributes: Ref<Attributes>
isDragging: Ref<boolean>
}Parameters
elementRef- Vue template ref or DOM element to track for pointer events.options- Optional configuration object
Options
type DragAttributesOptions = {
// when the element is unmounted clears all document event listeners.
// Set to false to continue dragging if the original container is removed
autoCleanup?: boolean
onPointerDown?: (event: PointerEvent) => void
onPointerMove?: (event: PointerEvent) => void
onPointerUp?: (event: PointerEvent) => void
}Returns
attributes- Reactive object containing position and size dataisDragging- Boolean indicating if element is currently being dragged
useDragSubject Creates a draggable element that can be dragged around the page.
The subject receives the same events of the target so you can act with the callbacks onEnter, onOver, onLeave, onDrop.
Everything is lazy, no events are fired or listened to unless they are useful.
function useDragSubject<T = unknown>(
elementRef: MaybeRefOrGetter<unknown>,
namespace: NameSpace,
item?: T,
options?: DragSubjectOptions<T>
): {
attributes: Ref<Attributes> // See later definition
isDragging: Ref<boolean>
isOver: Ref<boolean>
}Parameters
elementRef- Vue template ref to the draggable elementnamespace- Unique identifier that links the subject to its drop area.item- Optional data to pass with drag eventsoptions- Configuration options
Options
type DragSubjectOptions<T = unknown> = {
/**
* Automatically cleans up event listeners when the element is unmounted.
* Set to false to keep listeners active even if the original container is removed.
* @default true
*/
autoCleanup?: boolean
/**
* Callback function triggered when the draggable element enters a drop target.
* @param data - The data associated with the drag event.
* @param event - The original event object.
*/
onEnter?: ClientEventHandler<T>
/**
* Callback function triggered when the draggable element is moved over a drop target.
* @param data - The data associated with the drag event.
* @param event - The original event object.
*/
onOver?: ClientEventHandler<T>
/**
* Callback function triggered when the draggable element is dropped on a drop target.
* @param data - The data associated with the drag event.
* @param event - The original event object.
*/
onDrop?: ClientEventHandler<T>
/**
* Callback function triggered when the draggable element leaves a drop target.
* @param data - The data associated with the drag event.
* @param event - The original event object.
*/
onLeave?: ClientEventHandler<T>
}Returns
attributes- Reactive object containing position and size dataisDragging- Boolean indicating if element is currently being draggedisOver- Boolean indicating if element is over a drop target
useDragTarget
Creates a drop target area.
It fires the same events of the subject. you can act with the callbacks onEnter, onOver, onLeave, onDrop.
Everything is lazy, no events are fired or listened to unless they are useful
function useDragTarget<T = unknown>(
elementRef: MaybeRefOrGetter<unknown>,
namespace: NameSpace,
options?: UseDragTargetOptions<T>
): {
isDragging: Ref<boolean>
isOver: Ref<boolean>
item: Ref<T | null>
}Parameters
elementRef- Vue template ref to the drop target elementnamespace- Must match the namespace of the drag subjectoptions- Configuration options
Options
type UseDragTargetOptions<T> = {
onEnter?: ClientEventHandler<T>
onOver?: ClientEventHandler<T>
onLeave?: ClientEventHandler<T>
onDrop?: ClientEventHandler<T>
nested?: boolean // Default: true - when true only the topmost surface area will eb reactive
}Returns
isDragging- Boolean indicating if any item in this namespace is being draggedisOver- Boolean indicating if an item is over this targetitem- The currently dragged item data
useDragClone
Creates a visual clone that follows the cursor during drag operations.
function useDragClone(
elementRef: MaybeRefOrGetter<unknown>,
attributes: MaybeRefOrGetter<Attributes>,
options?: Options
): {
clone: Ref<HTMLElement | null>
removeClone: () => void
}Parameters
elementRef- Vue template ref to the original elementattributes- Attributes from useDragSubjectoptions- Configuration options
Options
type Options = {
cloneClass?: string // Default: 'clone'
}Types
Attributes
type Attributes = {
// The container rect data
container: {
x: number
y: number
width: number
height: number
}
// Event data
event: {
x: number
y: number
}
// Projected data of the container after translating it (used by the clone)
translated: {
x: number
y: number
}
// The x, y delta from the initial event
delta: {
x: number
y: number
}
}Best Practices
- Use Descriptive Namespaces - Choose meaningful names like
'user-contact-list'or'document-file-upload' - Handle Cleanup - The library automatically cleans up event listeners
- Touch Support - The library handles touch events automatically
License
MIT License - see LICENSE file for details.
