Skip to example

AnimateView: Reorder items

An example of using AnimateView to animate list items as they reorder, using Motion for React's view transition API.

React

Source code

"use client"

import { spring } from "motion"
import { AnimateView } from "motion/react-animate-view"
import { startTransition, useState } from "react"

export default function ReorderExample() {
    const [items, setItems] = useState(initialItems)

    const shuffle = () => {
        startTransition(() => {
            setItems((prev) => [...prev].sort(() => Math.random() - 0.5))
        })
    }

    return (
        <div className="reorder-container">
            <button className="reorder-shuffle" onClick={shuffle}>
                <ShuffleIcon />
                Shuffle
            </button>
            <div className="reorder-list">
                {items.map((item) => (
                    <AnimateView
                        key={item.id}
                        transition={{
                            type: spring,
                            visualDuration: 0.3,
                            bounce: 0.2,
                        }}
                    >
                        <div className="reorder-item">
                            <span
                                className="reorder-accent"
                                style={{ backgroundColor: item.color }}
                            />
                            <span className="reorder-label">{item.label}</span>
                        </div>
                    </AnimateView>
                ))}
            </div>
            <StyleSheet />
        </div>
    )
}

/** ==============   Icons   ================ */

function ShuffleIcon() {
    return (
        <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
        >
            <path d="m18 14 4 4-4 4" />
            <path d="m18 2 4 4-4 4" />
            <path d="M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22" />
            <path d="M2 6h1.972a4 4 0 0 1 3.6 2.2" />
            <path d="M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45" />
        </svg>
    )
}

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

const COLORS = [
    "#ff0088",
    "#dd00ee",
    "#9911ff",
    "#1e75f7",
    "#0cdcf7",
    "#8df0cc",
    "#ffaa00",
    "#00cc88",
]

const API_NAMES = [
    "animate",
    "spring",
    "stagger",
    "inView",
    "scroll",
    "hover",
    "press",
    "drag",
]

const initialItems = API_NAMES.map((name, i) => ({
    id: i,
    color: COLORS[i % COLORS.length],
    label: name,
}))

/** ==============   Styles   ================ */

function StyleSheet() {
    return (
        <style>{`
            .reorder-container {
                width: 100%;
                max-width: 340px;
                padding: 16px;
                background-color: var(--layer);
                border-radius: 16px;
                border: 1px solid var(--border);
                display: flex;
                flex-direction: column;
                gap: 16px;
            }

            .reorder-shuffle {
                align-self: center;
                padding: 8px 24px;
                background-color: var(--accent);
                color: var(--black);
                border: none;
                border-radius: 8px;
                font-size: 14px;
                font-weight: 600;
                cursor: pointer;
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .reorder-shuffle:hover {
                opacity: 0.9;
            }

            .reorder-list {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 8px;
            }

            .reorder-item {
                display: flex;
                align-items: center;
                gap: 12px;
                padding: 10px 14px;
                background-color: rgba(255, 255, 255, 0.05);
                border-radius: 10px;
            }

            .reorder-accent {
                width: 4px;
                height: 20px;
                border-radius: 2px;
                flex-shrink: 0;
            }

            .reorder-label {
                font-size: 14px;
                font-weight: 500;
                font-family: var(--font-mono);
                color: var(--white);
            }
        `}</style>
    )
}