Drag Reorder List
Smooth drag-to-reorder list with spring physics and animated gap
animationdragreorderlistinteractive
Install dependencies
$npm install framer-motionPreview
Source Code
"use client";
import { useState } from "react";
import { Reorder, motion } from "framer-motion";
interface DragItem {
id: string;
content: React.ReactNode;
}
interface DragReorderListProps {
items: DragItem[];
onReorder?: (items: DragItem[]) => void;
className?: string;
}
export default function DragReorderList({
items: initialItems,
onReorder,
className = "",
}: DragReorderListProps) {
const [items, setItems] = useState(initialItems);
const handleReorder = (newItems: DragItem[]) => {
setItems(newItems);
onReorder?.(newItems);
};
return (
<Reorder.Group
axis="y"
values={items}
onReorder={handleReorder}
className={`flex flex-col gap-2 ${className}`}
>
{items.map((item) => (
<Reorder.Item
key={item.id}
value={item}
whileDrag={{
scale: 1.03,
boxShadow: "0 20px 40px rgba(0,0,0,0.4)",
zIndex: 50,
}}
transition={{ type: "spring", stiffness: 300, damping: 25 }}
className="flex cursor-grab items-center gap-3 rounded-xl border border-white/10 bg-gray-900 px-4 py-3 active:cursor-grabbing"
>
{/* Drag handle */}
<motion.div className="flex flex-col gap-[3px] text-gray-500">
<div className="flex gap-[3px]">
<div className="h-1 w-1 rounded-full bg-current" />
<div className="h-1 w-1 rounded-full bg-current" />
</div>
<div className="flex gap-[3px]">
<div className="h-1 w-1 rounded-full bg-current" />
<div className="h-1 w-1 rounded-full bg-current" />
</div>
<div className="flex gap-[3px]">
<div className="h-1 w-1 rounded-full bg-current" />
<div className="h-1 w-1 rounded-full bg-current" />
</div>
</motion.div>
<div className="flex-1 text-sm text-white">{item.content}</div>
</Reorder.Item>
))}
</Reorder.Group>
);
}