---
title: Drag Order List
description: A draggable, reorderable list built using React, Motion One, and Tailwind CSS. Items can be rearranged vertically via drag-and-drop gestures, with smooth animation and visual feedback.
---

<ComponentPreview name="drag-order-list-demo" />

## Installation

<Tabs defaultValue="cli">

<TabsList>
  <TabsTrigger value="cli">CLI</TabsTrigger>
  <TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">

```bash
npx lightswind@latest add drag-order-list
```

</TabsContent>

<TabsContent value="manual">

<Steps>

<Step>Copy and paste the following code into your project.</Step>

```tsx
"use client";

import React, { useEffect } from "react";
import {
  useMotionValue,
  Reorder,
  useDragControls,
  motion,
  animate,
  DragControls,
} from "framer-motion";
import { GripVertical } from "lucide-react";

export interface DragItem {
  id: number;
  title: string;
  subtitle: string;
  date: string;
  link?: string;
}

interface DragOrderListProps {
  items: DragItem[];
  onReorder?: (items: DragItem[]) => void;
}

export function DragOrderList({ items, onReorder }: DragOrderListProps) {
  const [list, setList] = React.useState(items);

  useEffect(() => {
    if (onReorder) onReorder(list);
  }, [list]);

  return (
    <Reorder.Group
      axis="y"
      values={list}
      onReorder={setList}
      className="space-y-4 w-full max-w-2xl mx-auto"
    >
      {list.map((item) => (
        <DragOrderItem key={item.id} item={item} />
      ))}
    </Reorder.Group>
  );
}

function DragOrderItem({ item }: { item: DragItem }) {
  const y = useMotionValue(0);
  const boxShadow = useRaisedShadow(y);
  const dragControls = useDragControls();

  return (
    <Reorder.Item
      value={item}
      style={{ boxShadow, y }}
      dragListener={false}
      dragControls={dragControls}
      className="flex justify-between items-start p-4 bg-background 
     text-foreground rounded-xl border shadow-sm"
    >
      <div className="flex flex-col space-y-1 flex-1">
        <h2 className="text-lg font-semibold">{item.title}</h2>
        <p className="text-sm text-muted-foreground">{item.subtitle}</p>
        <span className="text-xs text-muted-foreground">{item.date}</span>
        {item.link && (
          <a
            href={item.link}
            target="_blank"
            rel="noopener noreferrer"
            className="mt-2 inline-block text-xs text-primarylw hover:underline"
          >
            View details about {item.title}
          </a>
        )}
      </div>
      <ReorderHandle dragControls={dragControls} />
    </Reorder.Item>
  );
}

function ReorderHandle({ dragControls }: { dragControls: DragControls }) {
  return (
    <motion.div
      whileTap={{ scale: 0.95 }}
      onPointerDown={(e) => {
        e.preventDefault();
        dragControls.start(e);
      }}
      className="cursor-grab active:cursor-grabbing p-2 text-muted-foreground"
    >
      <GripVertical />
    </motion.div>
  );
}

const inactiveShadow = "0px 0px 0px rgba(0,0,0,0.8)";

function useRaisedShadow(value: ReturnType<typeof useMotionValue>) {
  const boxShadow = useMotionValue(inactiveShadow);

  useEffect(() => {
    let isActive = false;
    return value.on("change", (latest) => {
      const wasActive = isActive;
      if (latest !== 0) {
        isActive = true;
        if (isActive !== wasActive) {
          animate(boxShadow, "5px 5px 15px rgba(0,0,0,0.15)");
        }
      } else {
        isActive = false;
        if (isActive !== wasActive) {
          animate(boxShadow, inactiveShadow);
        }
      }
    });
  }, [value, boxShadow]);

  return boxShadow;
}

```

</Steps>

</TabsContent>

</Tabs>

## Usage

```tsx
import { DragOrderList } from '@/components/lightswind/drag-order-list';
```

```tsx
import { DragOrderList } from '@/components/lightswind/drag-order-list';

const items = [
  {
    id: 1,
    title: "Task One",
    subtitle: "This is the first task",
    date: "2025-07-29",
    link: "https://example.com/task-1"
  },
  {
    id: 2,
    title: "Task Two",
    subtitle: "This is the second task",
    date: "2025-07-28"
  },
];

<DragOrderList
  items={items}
  onReorder={(newOrder) => console.log("Reordered items:", newOrder)}
/>
```
