Sortable

Drag-and-drop reordering for lists. Put drag listeners on SortableItemHandle so the rest of the row stays clickable. Supports vertical, horizontal, and grid strategies, plus keyboard reordering.

Asset pipeline

Ranked CDN assets with typed chips. Same source as add sortable-default.

Loading…

Installation

CLI
npx @sonojs/ui@latest add sortable
Also needsnpm i @dnd-kit/core@^6.3.1 @dnd-kit/sortable@^10.0.0 @dnd-kit/utilities@^3.2.2

Composition

structure
Sortable
├── SortableItem
│   └── SortableItemHandle
└── SortableOverlay (optional)

Usage

sortable.tsx
"use client"

import { useState } from "react"

import {
  Sortable,
  SortableItem,
  SortableItemHandle,
} from "@/components/ui/sortable"

export function Example() {
  const [items, setItems] = useState([
    { id: "1", label: "One" },
    { id: "2", label: "Two" },
  ])

  return (
    <Sortable
      value={items}
      onValueChange={setItems}
      getItemValue={(item) => item.id}
    >
      {items.map((item) => (
        <SortableItem key={item.id} value={item.id}>
          <div className="flex items-center gap-2">
            <SortableItemHandle>⋮⋮</SortableItemHandle>
            {item.label}
          </div>
        </SortableItem>
      ))}
    </Sortable>
  )
}

Props

PropTypeDefaultDescription
valueT[]—Controlled list of items.
onValueChange(value: T[]) => void—Called with the reordered array after a drop.
getItemValue(item: T) => string—Stable unique id for each item (used as the drag id).
strategy"vertical" · "horizontal" · "grid""vertical"Layout strategy for measuring and animating items.
onValueCommit(value: T[], meta) => void—Fires after a successful reorder with indexes and the previous value.
onMove(event) => void—Custom move handler. When set, skips the default arrayMove + onValueChange.

Drag only activates from SortableItemHandle. Items without a handle cannot be dragged.