javascript 63 lines · 8 steps

Drag-to-reorder lists in React

A React component that lets users reorder list items with the native HTML drag-and-drop API and three pieces of state.

Explained by highlit
1import { useState } from 'react';
2 
3export function ReorderableList({ initialItems }) {
4 const [items, setItems] = useState(initialItems);
5 const [draggingId, setDraggingId] = useState(null);
6 const [overId, setOverId] = useState(null);
7 
8 const handleDragStart = (event, id) => {
9 setDraggingId(id);
10 event.dataTransfer.effectAllowed = 'move';
11 event.dataTransfer.setData('text/plain', String(id));
12 };
13 
14 const handleDragOver = (event, id) => {
15 event.preventDefault();
16 event.dataTransfer.dropEffect = 'move';
17 if (id !== overId) setOverId(id);
18 };
19 
20 const handleDrop = (event, targetId) => {
21 event.preventDefault();
22 if (draggingId === null || draggingId === targetId) return;
23 
24 setItems((prev) => {
25 const next = [...prev];
26 const from = next.findIndex((item) => item.id === draggingId);
27 const to = next.findIndex((item) => item.id === targetId);
28 const [moved] = next.splice(from, 1);
29 next.splice(to, 0, moved);
30 return next;
31 });
32 };
33 
34 const handleDragEnd = () => {
35 setDraggingId(null);
36 setOverId(null);
37 };
38 
39 return (
40 <ul className="reorderable-list">
41 {items.map((item) => (
42 <li
43 key={item.id}
44 draggable
45 onDragStart={(e) => handleDragStart(e, item.id)}
46 onDragOver={(e) => handleDragOver(e, item.id)}
47 onDrop={(e) => handleDrop(e, item.id)}
48 onDragEnd={handleDragEnd}
49 className={[
50 'reorderable-item',
51 draggingId === item.id && 'is-dragging',
52 overId === item.id && draggingId !== item.id && 'is-over',
53 ]
54 .filter(Boolean)
55 .join(' ')}
56 >
57 <span className="drag-handle" aria-hidden="true">≡</span>
58 {item.label}
59 </li>
60 ))}
61 </ul>
62 );
63}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Tracking the dragged item and hover target in state lets you compute both the reorder and the visual feedback.
  2. 2Reordering immutably with a copied array plus splice keeps React's state updates predictable.
  3. 3The native HTML drag-and-drop API needs preventDefault on dragover and drop for a drop to register.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Drag-to-reorder lists in React — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code