To add drag-and-drop list reordering to React applications, follow these actionable steps:
- Install core dependencies: Use npm or yarn to add the base
dnd-kitpackages to you're project. The core library handles essential drag mechanics, and a sorting-specific package simplifies list rearrangement.npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities - Integrate sortable components and hooks: Import
DndContext,SortableContext,useSortable,arrayMove, andDragOverlayfrom the respective packages. - Configure drag context: Wrap your application or list container in
DndContextto manage drag interactions, provide a unique ID list forSortableContextto track sortable elements, and handle theonDragEndevent. - Build sortable items: Create a reusable
SortableItemcomponent that usesuseSortableto attach drag handlers and refs. - Render a drag overlay: Use
DragOverlayto display a floating copy of the dragged element, improving UX. - Update state with reordered data: Leverage
arrayMovefrom@dnd-kit/utilitiesto safely rearrange your list state when dragging completes.
Here’s a restructured, functional code example:
import React, { useState } from 'react';
import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, DragOverlay } from '@dnd-kit/core';
import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
interface SortableTaskProps {
id: string;
content: string;
}
const SortableTask = ({ id, content }: SortableTaskProps) => {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });
const dragStyle = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.3 : 1,
padding: '12px',
marginBottom: '8px',
backgroundColor: '#f0f9ff',
border: '1px solid #bae6fd',
borderRadius: '8px',
cursor: 'grab',
};
return (
<div ref={setNodeRef} style={dragStyle} {...attributes} {...listeners}>
{content}
</div>
);
};
const initialTaskList = [
{ id: 'task-write', content: 'Draft weekly report' },
{ id: 'task-code', content: 'Fix login validation' },
{ id: 'task-review', content: 'Review PR #241' },
];
const ReorderableTaskList = () => {
const [tasks, setTasks] = useState(initialTaskList);
const [activeTaskId, setActiveTaskId] = useState<string | null>(null);
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
const handleDragStart = (event: any) => {
setActiveTaskId(event.active.id);
};
const handleDragEnd = (event: any) => {
const { active, over } = event;
if (over && active.id !== over.id) {
setTasks((prev) => {
const oldIdx = prev.findIndex((t) => t.id === active.id);
const newIdx = prev.findIndex((t) => t.id === over.id);
return arrayMove(prev, oldIdx, newIdx);
});
}
setActiveTaskId(null);
};
const activeTask = activeTaskId ? tasks.find((t) => t.id === activeTaskId) : null;
return (
<div style={{ maxWidth: '400px', margin: '2rem auto', padding: '0 1rem' }}>
<h2 style={{ textAlign: 'center', marginBottom: '1.5rem' }}>Priority Task List</h2>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<SortableContext items={tasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
{tasks.map((task) => (
<SortableTask key={task.id} id={task.id} content={task.content} />
))}
</SortableContext>
<DragOverlay>
{activeTask ? (
<div style={{ padding: '12px', backgroundColor: '#ffffff', border: '2px solid #0ea5e9', borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.15)', cursor: 'grabbing' }}>
{activeTask.content}
</div>
) : null}
</DragOverlay>
</DndContext>
</div>
);
};
export default ReorderableTaskList;
This example adds keyboard accessibility support, uses a vertical sorting strategy, includes visual feedback for dragged items, and leverages arrayMove for safe state updates. The closestCenter collision detection ensures items reorder smoothly, and CSS.Transform handles positioning of sortable elements during drag operations.