Drag-and-drop — an interactive interface for dragging elements (kanban boards, list sorting).
Why it matters: Drag-and-drop is the most intuitive way to reorder items, move tasks between columns, or rearrange layouts. Applications like Trello, Notion, and Figma rely heavily on it. In React, the challenge is that the HTML5 DnD API is verbose and low-level — libraries like React DnD and @dnd-kit abstract away the complexity.
1. React DnD (based on HTML5 DnD API):
1import { DndProvider } from "react-dnd";2import { HTML5Backend } from "react-dnd-html5-backend";3import { useDrag, useDrop } from "react-dnd";45function DraggableItem({ id, text, moveItem }) {6 const [{ isDragging }, drag] = useDrag({7 type: "ITEM",8 item: { id },9 collect: (monitor) => ({10 isDragging: monitor.isDragging(),11 }),12 });1314 const [, drop] = useDrop({15 accept: "ITEM",16 hover: (draggedItem) => {17 if (draggedItem.id !== id) {18 moveItem(draggedItem.id, id);19 }20 },21 });2223 return (24 <div25 ref={(node) => drag(drop(node))}26 style={{ opacity: isDragging ? 0.5 : 1 }}27 >28 {text}29 </div>30 );31}3233function App() {34 const [items, setItems] = useState([35 { id: 1, text: "Task 1" },36 { id: 2, text: "Task 2" },37 { id: 3, text: "Task 3" },38 ]);3940 const moveItem = (fromId, toId) => {41 setItems(prev => {42 const fromIndex = prev.findIndex(i => i.id === fromId);43 const toIndex = prev.findIndex(i => i.id === toId);44 const updated = [...prev];45 const [moved] = updated.splice(fromIndex, 1);46 updated.splice(toIndex, 0, moved);47 return updated;48 });49 };5051 return (52 <DndProvider backend={HTML5Backend}>53 {items.map(item => (54 <DraggableItem key={item.id} {...item} moveItem={moveItem} />55 ))}56 </DndProvider>57 );58}
2. @dnd-kit (modern alternative — recommended):
1import { DndContext, closestCenter, useSensor, useSensors, PointerSensor } from "@dnd-kit/core";2import { SortableContext, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";3import { CSS } from "@dnd-kit/utilities";45function SortableItem({ id, text }) {6 const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });7 const style = { transform: CSS.Transform.toString(transform), transition };89 return (10 <div ref={setNodeRef} style={style} {...attributes} {...listeners}>11 {text}12 </div>13 );14}1516function SortableList({ items, onDragEnd }) {17 const sensors = useSensors(useSensor(PointerSensor));1819 return (20 <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>21 <SortableContext items={items} strategy={verticalListSortingStrategy}>22 {items.map(item => <SortableItem key={item.id} {...item} />)}23 </SortableContext>24 </DndContext>25 );26}
How to handle drag events:
onDragStart — when the user picks up an item.onDragOver — when the item is dragged over a drop zone.onDragEnd — when the item is released. This is where you update state.Alternatives: