ExamplesLists

Reorder grid

A drag-to-reorder grid using Motion for Vue's Reorder component, with spring layout animations and drag scaling.

Vue
Live exampleOpen

Source code

<script setup lang="ts">
import { Reorder } from 'motion-v'
import { ref } from 'vue'

/**
 * ==============   Props   ================
 */

interface Props {
    dragScale?: number
    stiffness?: number
    damping?: number
}

const props = withDefaults(defineProps<Props>(), {
    dragScale: 1.08,
    stiffness: 350,
    damping: 30,
})

/**
 * ==============   Data   ================
 */

const initialItems = Array.from({ length: 16 }, (_, index) => index + 1)

const items = ref(initialItems)
</script>

<template>
    <main class="reorder-stage">
        <Reorder.Group
            as="div"
            v-model:values="items"
            class="reorder-grid"
            aria-label="Reorderable grid"
        >
            <Reorder.Item
                v-for="item in items"
                :key="item"
                as="div"
                :value="item"
                class="reorder-item"
                :transition="{
                    type: 'spring',
                    stiffness: stiffness,
                    damping: damping,
                }"
                :whileDrag="{ scale: dragScale }"
                :style="{
                    backgroundColor: `var(--hue-${(item % 6) + 1})`,
                }"
            >
                {{ String(item).padStart(2, "0") }}
            </Reorder.Item>
        </Reorder.Group>
    </main>
</template>

<style>
.reorder-stage {
    display: flex;
    align-items: center;
    justify-content: center;
    touch-action: none;
}

.reorder-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
    width: min(76vw, 420px);
}

.reorder-item {
    display: grid;
    place-items: center;
    aspect-ratio: 1;
    color: var(--background);
    cursor: grab;
    font-family: var(--font-mono);
    font-size: clamp(11px, 2.2vw, 15px);
    font-variation-settings: "wght" 600;
    user-select: none;
}

.reorder-item:active {
    cursor: grabbing;
}
</style>

Related examples

Latest in Vue