Customizable native Vue3 drag-n-drop library with no dependencies. Includes Vue plugin that registers directives to configure draggable elements and drop zones.
This package is intended to just be a directive that wraps the browser's drag and drop API and combine it with Vue's reactive features. The actual HTML events are available in each of the event handler callbacks. It is recommended to still understand how the browser's API works to best decide how to wire-up the directives for your use case. MDN has a good primer on the browser API here.
npm i dragon-drop-vue
import { createApp } from 'vue'
import App from './App.vue'
import { DragonDropVue } from 'dragon-drop-vue'
const dragonDropOptions = {
dragOverDebounceMs: 300,
debugLog: true,
}
createApp(App).use(DragonDropVue, dragonDropOptions)
<template>
<main>
<template v-for="column in columns">
<div v-drop="{ dragData: column, onDragEnter: onDragEnter, onDrop: onDrop }"></div>
<div v-drag="{ dragData: column, dragImage: dragImage, onDragStart: onDragStart }">{{ column }}</div>
</template>
</main>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { DragonDropVueDragOptions, DragonDropVueOptions } from 'dragon-drop-vue'
const columns = ref([0, 1, 2, 3, 4, 5, 6])
const dragging = ref<number | undefined>(undefined)
const image = new Image()
image.src = 'dragon.png'
const dragImage = {
image,
xOffset: 30,
yOffset: 0,
}
function onDragStart(domEl: HTMLElement, dragEvent: DragEvent, dragOptions: DragonDropVueDragOptions<number>, options: DragonDropVueOptions) {
dragging.value = dragOptions.dragData
}
function onDragEnter(domEl: HTMLElement, dragEvent: DragEvent, dragOptions: DragonDropVueDragOptions<number>, options: DragonDropVueOptions) {
// do not allow a draggable element to be dropped on itself
var dragIndex = this.dragging ?? 0
var dropIndex = dragOptions.dragData ?? 0
return dragIndex !== dropIndex
}
function onDrop(domEl: HTMLElement, dragEvent: DragEvent, dragOptions: DragonDropVueDragOptions<number>, options: DragonDropVueOptions) {
// implement drop behavior
}
</script>
Property | Type | Description |
---|---|---|
debugLog |
boolean or undefined |
Print additional debugging information to the console. All drag and drop events are printed. This also enables the Info log level of native-event-vue . |
dragDirectiveName |
string or undefined |
Optionally specify what to register for the drag directive. By default this is drag and the directive would be v-drag . |
dropDirectiveName |
string or undefined |
Optionally specify what to register for the drag directive. By default this is drop and the directive would be v-drop . |
dragClass |
string or undefined |
Custom class that will be added to all elements with the drag directive. ddv-draggable is also always added. |
dropClass |
string or undefined |
Custom class that will be added to all elements with the drop directive. ddv-dropzone is also always added. |
draggingClass |
string or undefined |
Custom class that will be added to the element currently being dragged. ddv-dragging is also always added. |
dragOverClass |
string or undefined |
Custom class that will added to the element currently being dragged over. ddv-ddv-dragging-over is also always added. |
dragOverDebounceMs |
number or undefined |
Optionally override the debounce period for the dragover event. By default, this is set to 500ms . Setting this to 0 will turn off debouncing of the dragover event. This can also be overridden by passing the same option to the object bound to the drop directive. The directive value will take precedence. |
dragOverDebounceMode |
DebounceMode or undefined |
Optionally override the debounce mode used to debounce the dragover event. By default, MaximumFrequency is used and this will debounce the event and only call the vent handler at most once during the debounce timeout. This can also be overridden by passing the same option to the object bound to the drop directive. The directive value will take precedence. |
The same options interface is used for both the drag and drop directive but some event handlers on apply to one or the other.
The DragonDropVueDragOptions
type has an optional type constraint for the type of the supplied drag data that will default to any
.
All event handler properties are of the following type.
(domEl: HTMLElement, dragEvent: DragEvent, dragOptions: DragonDropVueDragOptions<T>, options: DragonDropVueOptions) => boolean | undefined
Property | Type | Description |
---|---|---|
dragData |
Generic type constraint or any |
Any piece of data to pass to each drag and drop event handler. |
dragImage |
DragonDropVueDragImageOptions |
Optional drag image override. |
onDragStart |
Drag/drop event handler | dragstart event handler |
onDragEnd |
Drag/drop event handler | dragend event handler |
onDragOver |
Drag/drop event handler | dragover event handler |
onDragEnter |
Drag/drop event handler | dragenter event handler |
onDragLeave |
Drag/drop event handler | dragleave event handler |
onDrop |
Drag/drop event handler | drop event handler |
dragOverDebounceMs |
number or undefined |
Optionally override the debounce period for the dragover event. By default, this is set to 500ms . Setting this to 0 will turn off debouncing of the dragover event. This will take precedence over the same option on the plugin options. |
dragOverDebounceMode |
DebounceMode or undefined |
Optionally override the debounce mode used to debounce the dragover event. By default, MaximumFrequency is used and this will debounce the event and only call the vent handler at most once during the debounce timeout. This will take precedence over the same option on the plugin options. |
When drag data is specified to the drag directive it is set on the data transfer of the browser events as JSON. The drop directive will also retrieve the drag data from the date transfer object, deserialize it and set it as the drag data on the options passed to the onDrop
callback.
The drag directive contains the necessary boilerplate to take a Vue component definition and prop values to create an element to use as the drag image. It is also automatically removed from the DOM as part of onDrop
handling.
<template>
<main>
<template v-for="column in columns">
<div v-drop="{ dragData: column, onDragEnter: onDragEnter, onDrop: onDrop }"></div>
<div v-drag="{ dragData: column, onDragStart: onDragStart }">{{ column }}</div>
</template>
</main>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { DragonDropVueDragOptions, DragonDropVueOptions } from 'dragon-drop-vue'
import CustomComponent from '@/components/CustomComponent.vue'
const columns = ref([0, 1, 2, 3, 4, 5, 6])
const dragging = ref<number | undefined>(undefined)
function onDragStart(domEl: HTMLElement, dragEvent: DragEvent, dragOptions: DragonDropVueDragOptions<number>, options: DragonDropVueOptions) {
dragging.value = dragOptions.dragData
dragOptions.dragImage = {
rootComponent: CustomComponent,
rootComponentProps: { column: dragOptions.dragData },
}
}
</script>
- Rev development dependencies. This addresses the security vulnerabilities reported in package
ip
.
- Fix for
dragover
event not gettingpreventDefault
called on it when debounced to ensure thedrop
event fires. - Update to v1.4.0 of
native-event-vue
- Do not log updated lifecycle hooks when it did not result in the event handler being attached or detached.
- Remove drop handling in beforeMount and updated lifecycle hooks when the bound value changes to
false
- Remove all classes and event handlers instead of just setting the
draggable
attribute tofalse
when the drag directive binding is set tofalse
- Migrate to
native-event-vue
to manage adding and removing HTML native events to DOM elements and leverage its debouncing capabilities on thedragover
event. - The
dragover
event is now debounced by default and the attached handler will only run at most once every 500ms. The debounce time and debounce mode can be configured on the plugin options. - Additional source documentation.
- Automated tests
- Add additional debug logging to track when directive lifecycle hooks fire and DOM state after processing.
- Add additional debug logging to track when HTML event handlers are added or removed.
- Improve debug log formatting.
- Update development dependencies.
- Add ability to specify a Vue component and property values for the drag image.
- Parse data transfer drag data from drop event and pass to
onDrop
via the drag options drag data if drag data does not already exist.
- Plugin options can no longer be undefined. The default value is now an empty object.
- Requires node v18 or greater
- Documentation update
- improve plugin and directive typing
- allow directive names to be overridden via plugin options
- export DropEffect
- react to options changes that can turn draggable on/off
- remove console.log
- allow false to turn off drag and drop directives
- Initial release