Skip to content

Drop

Drop defines an area into which data can be dropped. Targets can be nested to form hierarchies of arbitrary depth; the foremost participating target under the pointer becomes active.

Events

EventDescription
dragenterThis component becomes the foremost participating target.
dragleaveThis component stops being the foremost participating target.
dragoverThe pointer moves while this component is the foremost participating target.
dragendThe operation ends while this component is the active target, including cancellation with Escape.
dropA permitted operation is released on this component.

These events receive a DnDEventPayload.

Props

PropType / DefaultDescription
tagString or component ('div')Root element or Vue component. A component must render one HTML root element; its props, attributes, listeners, and slots are forwarded.
accepts-typeString, Number, Array, Function, or null (null)Accepted drag type, accepted type array, or (type) => boolean predicate. null accepts every type.
accepts-dataFunction (() => true)(data, type) => boolean predicate evaluated for participating drag data.
modeString ('copy')Event name sent back to the source after a successful drop. The documented modes are copy and cut.
drag-image-opacityNumber (0.7)Opacity applied to a custom drag image supplied by this target.

Slots

SlotPropsDescription
defaultProps forwarded by a component passed to tagContent rendered inside the target root.
drag-imagetype, dataOptional image used while this participating target is active.

Other named slots are forwarded when tag is a Vue component.

CSS classes

ClassApplied when
dnd-dropAlways on the Drop root.
type-allowed / type-forbiddenThe active drag type is accepted or rejected.
drop-in / drop-outThis component is or is not the foremost participating target.
drop-allowed / drop-forbiddenParticipating drag data is accepted or rejected.

The state classes are present only while a drag is active where their value can be determined. A type-forbidden target does not become the active target; an accepting ancestor may become active instead.

Modes

The target's mode describes the successful operation from the source's perspective:

  • copy leaves source state unchanged unless the application chooses otherwise.
  • cut normally removes or updates the source item.

After drop is emitted on the target, the same payload is emitted on the source Drag using the mode as the event name. The library does not mutate application state, so implement @cut when the source item should be removed.

vue
<Drag :data="item" @cut="remove(item)">
  {{ item.label }}
</Drag>

<Drop mode="cut" @drop="receive">
  Move here
</Drop>

A mode is not made invalid by the absence of a source listener. Use the documented copy and cut modes so Vue can validate the declared source events.

Copy and cut modes

Copy leaves the source intact. Cut emits back to the source so it can be removed.

One
Two
Three
Copy
Cut
View example code

Template

vue
<div class="dnd-demo__row">
  <Drag
    v-for="item in items"
    :key="item"
    class="dnd-demo__item"
    :data="item"
    @cut="remove(item)"
  >
    {{ item }}
  </Drag>
</div>
<div class="dnd-demo__grid" style="margin-top: 1rem">
  <Drop
    class="dnd-demo__zone"
    mode="copy"
    @drop="record('Copied', $event)"
  >
    <span class="dnd-demo__label">Copy</span>
  </Drop>
  <Drop
    class="dnd-demo__zone"
    mode="cut"
    @drop="record('Cut', $event)"
  >
    <span class="dnd-demo__label">Cut</span>
  </Drop>
</div>

TypeScript

ts
import { ref } from 'vue';
import { Drag, Drop } from 'vue-easy-dnd';
import type { DnDEventPayload } from 'vue-easy-dnd';

const initialItems = ['One', 'Two', 'Three'];
const items = ref([...initialItems]);
const status = ref('Choose a target');

const remove = (item: string) => {
  items.value = items.value.filter(value => value !== item);
};
const record = (action: string, event: DnDEventPayload) => {
  status.value = `${action} ${String(event.data)}`;
};
const reset = () => {
  items.value = [...initialItems];
  status.value = 'Choose a target';
};

Restricting droppable data

accepts-type determines whether a target participates in an operation. Once it participates, accepts-data receives (data, type) and determines whether dropping is permitted.

vue
<Drop
  accepts-type="number"
  :accepts-data="data => typeof data === 'number' && data % 2 === 0"
  @drop="receiveEvenNumber"
>
  Even numbers only
</Drop>
Filter drag data

All items share a type; accepts-data decides whether each value is allowed.

1
2
3
4
5
Copy even numbers
Copy odd numbers
Cut any number
View example code

Template

vue
<div class="dnd-demo__row">
  <Drag
    v-for="number in numbers"
    :key="number"
    class="dnd-demo__item"
    type="number"
    :data="number"
    @cut="remove(number)"
  >
    {{ number }}
  </Drag>
</div>
<div class="dnd-demo__grid" style="margin-top: 1rem">
  <Drop
    class="dnd-demo__zone"
    :accepts-data="isEven"
    @drop="record('Even', $event)"
  >
    <span class="dnd-demo__label">Copy even numbers</span>
  </Drop>
  <Drop
    class="dnd-demo__zone"
    :accepts-data="isOdd"
    @drop="record('Odd', $event)"
  >
    <span class="dnd-demo__label">Copy odd numbers</span>
  </Drop>
  <Drop
    class="dnd-demo__zone"
    mode="cut"
    @drop="record('Removed', $event)"
  >
    <span class="dnd-demo__label">Cut any number</span>
  </Drop>
</div>

TypeScript

ts
import { ref } from 'vue';
import { Drag, Drop } from 'vue-easy-dnd';
import type { DnDEventPayload, DragData } from 'vue-easy-dnd';

const numbers = ref([1, 2, 3, 4, 5]);
const status = ref('Try each target');
const isEven = (data: DragData) => typeof data === 'number' && data % 2 === 0;
const isOdd = (data: DragData) => typeof data === 'number' && data % 2 === 1;
const remove = (number: number) => {
  numbers.value = numbers.value.filter(value => value !== number);
};
const record = (target: string, event: DnDEventPayload) => {
  status.value = `${target}: ${String(event.data)}`;
};
const reset = () => {
  numbers.value = [1, 2, 3, 4, 5];
  status.value = 'Try each target';
};