Skip to content

Drag and Drop Components

Purpose

These components provide consistent UI for drag and drop interactions:

  • DraggableItem — Wrapper for sortable items
  • DragHandle — Accessible drag trigger
  • DroppableZone — Drop target with visual feedback
  • SortableList — Container for sortable items
  • EmptyDropZone — Placeholder for empty drop areas

Built on @dnd-kit for accessible, performant drag and drop.

When to use

Use these components with the useDragAndDrop hooks for:

  • Sortable lists and tables
  • Kanban boards
  • Reorderable navigation items
  • File organization interfaces

DraggableItem

Wrapper that makes an element draggable and sortable.

tsx
import { DraggableItem } from '@/shared/ui/components/DragAndDrop'

<DraggableItem id={item.id}>
  <div className="p-4 border rounded">
    {item.title}
  </div>
</DraggableItem>

Props

PropTypeDefaultDescription
idUniqueIdentifierRequiredUnique item ID
childrenReactNodeRequiredItem content
dataRecord<string, unknown>-Additional drag data
disabledbooleanfalseDisable dragging
isOverlaybooleanfalseRender as drag overlay

DragHandle

A dedicated drag trigger when only part of an item should be draggable.

tsx
import { DragHandle } from '@/shared/ui/components/DragAndDrop'
import { GripVertical } from 'lucide-react'

<DragHandle listeners={listeners} attributes={attributes}>
  <GripVertical className="h-4 w-4" />
</DragHandle>

Props

PropTypeDescription
listenersSortableListenersFrom useSortable
attributesSortableAttributesFrom useSortable
disabledbooleanDisable the handle

DroppableZone

A container that accepts dropped items with visual feedback.

tsx
import { DroppableZone } from '@/shared/ui/components/DragAndDrop'

<DroppableZone id="column-1" isOver={isOverColumn1}>
  {items.map(item => <DraggableItem key={item.id} id={item.id} />)}
</DroppableZone>

Props

PropTypeDescription
idUniqueIdentifierZone identifier
isOverbooleanWhether being dragged over
childrenReactNodeZone content

SortableList

A generic container for sortable items.

tsx
import { SortableList } from '@/shared/ui/components/DragAndDrop'

<SortableList
  items={tasks}
  getItemId={(task) => task.id}
  renderItem={(task) => <TaskCard task={task} />}
  direction="vertical"
/>

Props

PropTypeDefaultDescription
itemsT[]RequiredItems array
getItemId(item: T) => UniqueIdentifierRequiredID extractor
renderItem(item: T, index: number) => ReactNodeRequiredItem renderer
direction'vertical' | 'horizontal''vertical'List direction

EmptyDropZone

Placeholder for empty droppable areas.

tsx
import { EmptyDropZone } from '@/shared/ui/components/DragAndDrop'

<EmptyDropZone message="Drop tasks here" isOver={isOver} />

Props

PropTypeDefaultDescription
messagestring'Drop items here'Placeholder text
isOverbooleanfalseHighlight when dragged over