vue-arrange
v1.5.0
Published
Component library to drag and drop items across lists in Vue3. Try out [here](https://vuereka.github.io/vue-arrange/):
Maintainers
Readme
Vue-arrange: Arrangeable lists for Vue3
Component library to drag and drop items across lists in Vue3. Try out here:
Features:
- Rearranging a component list. Dragging/dropping items from one list to another.
- Nested lists (for making kanbans, see example)
- Recursively stackable, see filesystem example
- Fully customizable
- sensible defaults for "homing effect" and sliding list transitions
- Supports grab handles for list elements.
- Interactive elements such trash bin.
- Utility-class (Tailwind) friendly
- Completely built in Typescript. Supports generic items for any type of list.
- lightweight on dependencies
Usage
To install
npm add vue-arrangeTo run the example app
- clone the package and install dependencies
npm run dev
Exports:
Component ArrangeableList <PayloadType>
PayloadType is the generic type of the items in the list.
Props:
- list:
<PayloadType[]>list of items to arrange. - listKey:
<key of PayloadType>, optional;- Unique identifier for items.
- If not given, one gets automatically generated.
- identifier:
<TargetIdentifier>, optional- Unique name of the list. Defaults to an unnamed symbol.
- group:
<TargetIdentifier>, optional- Group the list belongs to. Items can be moved across member lists of this group.
- targets:
<TargetIdentifier | TargetIdentifier[]>, optional- By supplying one or more targets, items from this list can only be moved to those groups/lists.
- tag:
<string>, default:'ul'- HTML tag to use for the rendered list. E.g.
'ol'or'div'.
- HTML tag to use for the rendered list. E.g.
- listItemTag:
<string>, default:'li'- HTML tag to use for rendered list items.
- meta: , optional
- any information you wish to send along with items that get picked up.
- options:
<ArrangeableOptions>, optional; options passed to the ArrangeableList.- defaultItemClass:
<string>- css classes to place on all list items.
- pickedItemClass:
<string>- css classes to place on the original of the list item being picked up.
- By default: 'invisible' built-in class (see below).
- listTransition:
<TransitionGroupProps>- Transition props for the list, dictating how moving, removing and adding items to the list looks.
- Defaults to
{moveClass: "transition-all", leaveActiveClass: "absolute"}See built-in classes below. - See Vue TransitionGroup API documentation: https://vuejs.org/api/built-in-components.html#transitiongroup.
- hoverTransitionClass:
<string>- CSS classes to apply for transition instructions about how the item transitions to the hovering state.
- hoverClass:
<string>- CSS classes to shape the item in its lifted state.
- homingEffect:
<string | boolean>, defaulttrue/homing-effect- If
booleanandtrue, applies default classhoming-effectas the transition to bring the hovering item to its destination. - If
string, applies given CSS classes as the homing effect. - If
false, no homing effect.
- If
- handle:
<boolean | string>, defaultfalse- Indicate if the elements should be only dragged by a handle element. If
true, any descendant elements with property:data-handleare used as a handle. If it is set to astring, thedata-handleof the handle should be set to that string.
- Indicate if the elements should be only dragged by a handle element. If
- liftDelay:
<number>, default0- time to wait after clicking before the item gets lifted up and starts hovering. Useful if single click needs to be used for something else.
- defaultItemClass:
See ArrangeableProps type below
Slots:
#before: template to display something before the list of items.- Props:
arrangedItems: the list of items as it is rendered now.
- Props:
#default: template for the listed items;- Props:
item: the list itemarrangedItems: the list of items as it is rendered now.
- Props:
#after: template to display something after the list of items.- Props:
arrangedItems: the list of items as it is rendered now.
- Props:
Events emitted:
@lift-item: fired when an item is being picked up out of this list. Payload:MovingItem.@drop-item: fired when an item from this list is dropped somewhere. Payload:MovingItem.
Notes
- The
drop-itemhook is required to update the actual list. If not, the list restores to its original order. - Can be customized using options (see below).
- class options can take any list of (utility) classes like they would be normally passed to a component.
- There is a default transition for the list, this can be overridden by with the listTransition option.
- by default, items can only be moved within the same list.
- It can be used both by touch devices, mouse and any other type of pointer, as it uses PointerEvents. This is still experimental. It puts
touch-action: 'none'css class on the document, to prevent interference from the browser gestures.
Composable useMovingItem<PayloadType>()
Exposes:
movingItem, of ref-typeMovingItem<PayloadType> | undefined; the item currently being dragged around by the user from any list.isMoving(item: PayloadType) => boolean; test whetheritemis currently being dragged.movingItemCanTarget(targets: Array<TargetIdentifier | undefined>) => booleantests whether the movingItem has one of the targets given.
const { movingItem, isMoving } = useMovingItem<MyObjectType>();Types
MovingItem<PayloadType>
Information about what is/was being dragged/dropped.
type MovingItem<PayloadType extends object> = {
payload: PayloadType; // The item object being moved.
hoverElement?: Ref<HTMLElement>; // the element ref of the hovering item.
origin: Target<PayloadType>; // the list from which it was picked up as it was before the item was picked up.
destination: Target<PayloadType>; // the list where the item is hovering or being dropped. It includes the new item.
targets: Array<TargetIdentifier>; // the names/groups of the lists where this item can be dropped.
};type TargetIdentifier = string | number | symbol;type Target<PayloadType> = {
identifier: TargetIdentifier; // unique id
group?: TargetIdentifier; // shared id for lists of the same group (such as kanban columns)
type: "list" | "dropzone"; // dropzones are used to interact with listitems outside of lists.
listItems: PayloadType[]; // the elements of the list.
index: number; // The index of the lifted item.
meta: any; // any other information you may want to send to the recipient.
};ArrangeableProps<PayloadType>
See above for description.
type ArrangeableProps<PayloadType extends object> = {
options?: ArrangeableOptions;
list: PayloadType[];
listKey?: string;
identifier?: TargetIdentifier;
meta?: any;
group?: TargetIdentifier;
targets?: TargetIdentifier | Array<TargetIdentifier>;
};type ArrangeableOptions = {
defaultItemClass?: string;
pickedItemClass?: string;
listTransition?: TransitionGroupProps;
hoverTransitionClass?: string;
hoverClass?: string;
homingEffect?: string | boolean;
handle?: boolean | string;
};CSS classes used for defaults
These classes are shipped to be used as defaults:
.arrangeable-list__transition-all {
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.arrangeable-list__transition-all-but-location {
transition-property: opacity, transform, box-shadow, background-color,
border-color, color, fill, stroke, padding, margin;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.arrangeable-list__absolute {
position: absolute;
}
.arrangeable-list__invisible {
visibility: hidden;
}
.arrangeable-list__homing-effect {
transition-property: all;
top: var(--landingzone-top) !important;
left: var(--landingzone-left) !important;
}To include them in a project, add vue-arrange to the css section of the vue/nuxt config like this:
css: [
//...
'vue-arrange/dist/vue-arrange.css',
],Example usage
Simple example without typescript.
<script setup>
import { ref } from "vue";
import { ArrangeableList } from "vue-arrange";
const twColors = ref([
{ name: "red", color: "#fecaca" },
{ name: "orange", color: "#fed7aa" },
{ name: "amber", color: "#fde68a" },
{ name: "yellow", color: "#fef08a" },
]);
const dropItem = ({ destination }) => {
twColors.value = destination.list;
};
</script>
<template>
<ArrangeableList
:list="twColors"
:options="{
hoverClass: 'hover',
}"
@drop-item="dropItem"
v-slot="{ item }"
>
<div
style="height: 40px;width: 160px;border-radius: 8px;"
:style="item.color"
>
{{ item.name }}
</div>
</ArrangeableList>
</template>
<style>
.hover {
opacity: 0.65;
}
</style>See example folder for a complete example using typescript and tailwindcss.

