The Reorder components can be used to create drag-to-reorder layouts, like reorderable tabs, todo lists or grids.
Reorder.Group automatically detects whether its items are arranged horizontally, vertically, or across both dimensions.
<script setup>
import { Reorder } from "motion-v"
const items = ref([0,1,2,3])
</script>
<template>
<Reorder.Group v-model:values="items">
<Reorder.Item v-for="item in items" :key="item" :value="item">
{{item}}
</Reorder.Item>
</Reorder.Group>
</template>
Usage
Every reorderable layout is wrapped in the Reorder.Group component.
<script setup>
import { Reorder } from "motion-v"
</script>
<template>
<Reorder.Group>
</Reorder.Group>
</template>
By default, this is rendered as a <ul>, but this can be changed with the as prop.
<Reorder.Group as="ol">
Reorder.Group must be passed the array of values in your reorderable layout via the values prop.
Additionally, a onUpdate:values event will fire with the latest calculated order. For items to reorder, this must update the values state.
<script setup>
import { Reorder } from "motion-v"
const items = ref([0,1,2,3])
</script>
<template>
<Reorder.Group v-model:values="values">
</Reorder.Group>
</template>
To render each reorderable item, use Reorder.Item, passing it the value it represents via the value prop.
<script setup>
import { Reorder } from "motion-v"
const items = ref([0,1,2,3])
</script>
<template>
<Reorder.Group v-model:values="items">
<Reorder.Item v-for="item in items" :key="item" :value="item">
{{ item }}
</Reorder.Item>
</Reorder.Group>
</template>
Now, when items are dragged and reordered, onUpdate:values will fire with a new order.
Drag axis
Reorder.Group automatically detects whether its items are arranged horizontally, vertically, or across both dimensions, and sets the axis of reordering accordingly: "x" for rows, "y" for columns and "xy" for grids or wrapped lists.
It's possible to override the detected axis with the axis prop.
<Reorder.Group axis="xy" v-model:values="items" class="grid">
<Reorder.Item v-for="item in items" :key="item" :value="item">
{{ item }}
</Reorder.Item>
</Reorder.Group>
Note: When the axis is "x" or "y", all Reorder.Item components will visibly move only on this axis. To allow visual motion (but not reordering) on both axes, pass the drag prop to child Reorder.Item components.
Layout animations
Reorder.Item components are already configured to perform layout animations, so if new items are added or removed to the reorderable layout, surrounding items will animate to their new position automatically.
Exit animations
AnimatePresence can be used as normal to animate items as they enter/leave the Vue tree.
<AnimatePresence>
<Reorder.Item
v-for="item in items"
:key="item"
:initial="{ opacity: 0 }"
:animate="{ opacity: 1 }"
:exit="{ opacity: 0 }"
/>
</AnimatePresence>
Drag triggers
By default, all of a Reorder.Item will be draggable. useDragControls can be used to define a different component to act as a drag trigger.
<script>
import { Reorder, useDragControls } from "motion-v"
const controls = useDragControls()
</script>
<template>
<Reorder.Item
:value="value"
:dragListener="false"
:dragControls="controls"
>
<div
class="reorder-handle"
@pointerdown="(e) => controls.start(e)"
/>
</Reorder.Item>
</template>
Auto-scroll lists
If Reorder.Item components are within a scrollable container, that container will automatically scroll when an item is dragged towards its top or bottom edge. The closer to the edge of the container, the faster the scroll.
z-index
Reorder.Item will automatically set a z-index style on the currently dragged item so it appears above the surrounding items.
However, z-index only affects items with position !== "static". So to enable this effect ensure the position of the Reorder.Item is set to relative or absolute.
API
Reorder.Group
as
Default: "ul"
The underlying element for Reorder.Group to render as.
<Reorder.Group as="div"></Reorder.Group>
axis
Default: Automatically detected
The axis of reordering: "x", "y" or "xy". By default, Reorder.Group detects the axis from the layout of its items — "x" for horizontal rows, "y" for vertical columns and "xy" for grids or wrapped lists. Pass the axis prop to override the detected axis.
values
The values array that will be reordered. Each item in this list must match a value passed to each Reorder.Item.
onUpdate:values
A callback that will fire when items are detected to have reordered. The provided newOrder should be passed to a values state update function.
<script setup>
const items = ref([0,1,2,3])
</script>
<template>
<Reorder.Group v-model:values="items"/>
</template>
Reorder.Item
Reorder.Item components accept all motion component props in addition to the following:
as
Default: "li"
The element for Reorder.Item to render as.
value
When onUpdate:values is called, this is the value that will be passed through in the newly ordered array.