Drag & Drop

Sortable and reorderable interactions for lists, cards, and simple boards.

Overview

Drag & Drop provides accessible sortable/reorderable UI for dashboards and task lists. It is not a file-upload drop zone — use file-upload for that.

The implementation wraps @dnd-kit for pointer, touch, and keyboard sensors, sortable strategies, and live region announcements. Prefer DragDropHandle so nested buttons, links, and inputs stay interactive.

Keyboard: focus the handle, press Space/Enter to pick up, use arrow keys to move, Space/Enter to drop, Escape to cancel. Install with vinyaas add drag-and-drop or via vinyaas add --catalog dashboard.

Preview

Task A
Task B
Task C
Task D

Customize

Orientation
Activator
Disable Task C
Show Position

Installation

Add the component with the CLI. It copies the files in and installs anything they depend on.

npx vinyaas add drag-and-drop

Usage

import { useState } from "react"; import { DragDrop, DragDropHandle, DragDropItem, DragDropList, } from "@/components/ui/drag-and-drop"; export function TaskList() { const [items, setItems] = useState(["Task A", "Task B", "Task C", "Task D"]); return ( <DragDrop items={items} onReorder={setItems}> <DragDropList> {items.map((item) => ( <DragDropItem key={item} id={item} className="flex items-center gap-2 p-2"> <DragDropHandle aria-label={`Reorder ${item}`} /> <span>{item}</span> </DragDropItem> ))} </DragDropList> </DragDrop> ); }

Examples

Basic sortable list

Reorder items with a drag handle. Not a file-upload drop zone.

Task A
Task B
Task C
Task D

Drag handle and disabled items

Handles stay keyboard-focusable. Disabled items cannot start a drag.

Task A
Task B
System TaskLocked
Task D

Whole-item drag

Omit DragDropHandle to make the entire row the drag activator.

Inbox triage

Drag anywhere on the row — no separate handle.

Design review

Drag anywhere on the row — no separate handle.

Ship checklist

Drag anywhere on the row — no separate handle.

Horizontal chips

Use orientation="horizontal" for pill or chip reorder rows.

Design
Build
Review
Ship
Iterate

Priority queue

Numbered ranks update as items move — useful for triage and backlogs.

1P0 — Production incident
2P1 — Payment retries
3P2 — Empty-state copy
4P3 — Favicon refresh

Attachment order

Reorder files before upload or submit. Pair with file-upload for picking files.

brief.pdf

Attachment order

File

moodboard.png

Attachment order

File

spec.docx

Attachment order

File

recording.mp4

Attachment order

File

Playlist / queue

Compose a bordered shell around DragDropList for media queues.

Episode queue

Drag to change playback order.

5 clips

1Intro sting
2Chapter 1
3Interview A
4Break bumper
5Outro

Multiple containers

Move items between Todo and Done lists with a shared root.

Todo

Task A
Task B

Done

Task C
Task D

In practice

A Kanban-style sprint board: three columns, card composition with Badge and Button, and size-stable drag overlays across containers.

Sprint board

Multi-container DragDrop — cards keep their size while dragging.

Kanban

Backlog

3
Onboard billing

Wire Stripe webhooks and receipt emails.

Finance5
SK
Sidebar polish

Collapsed labels + rounded demo shells.

UI3
AR
Theme tokens

Align chart colors with primary.

Design2
SK

In progress

2
CLI dry-run

Verify catalog installs before write.

Tooling2
MK
A11y checklist

Keyboard, focus, and reduced motion.

Docs3
JL

Done

1
Release notes

Ship v1.3.0 changelog bullets.

Docs1
AR

API

Other attributes for the underlying element are passed through.

NameTypeDefaultDescription
items / onReorderUniqueIdentifier[] | Record<string, UniqueIdentifier[]>—DragDrop: controlled item order. Use an array for one list, or a record of arrays for multiple containers.
idstring—DragDrop: stable id for accessibility markup. Defaults to React useId() so server and client match.
orientation"vertical" | "horizontal""vertical"DragDrop: sorting axis and drop indicator direction.
disabledIdsUniqueIdentifier[]—DragDrop: item ids that cannot be dragged.
id / itemsstring / UniqueIdentifier[]—DragDropList: container id and that container’s ids (required for multiple containers).
id / disabledUniqueIdentifier / boolean—DragDropItem: sortable identity and optional disabled state.
aria-labelstring"Reorder"DragDropHandle: accessible name for the activator control.

Accessibility

Drag handles are native buttons with accessible names. @dnd-kit provides sortable keyboard interaction and live-region announcements for drag start, over, end, and cancel.

  • Tab reaches the handle. Space/Enter picks up; arrows move; Escape cancels.
  • Focus-visible rings use --ring tokens on the handle.
  • Drop targets show an insertion indicator line in addition to item movement.
  • Disabled items expose disabled handles and data-disabled on the item.
  • Touch activation uses a short delay so page scroll remains usable.
  • Item transitions respect prefers-reduced-motion.
  • Multiple containers accept items as a record of id arrays (Kanban-style boards). The drag overlay snapshots the active item and locks its width/height so cards do not shrink while dragging. Keep application state in the parent — this component does not persist order.