Sortable
An interaction wrapper for drag-and-drop reordering
A
B
C
const [items, setItems] = useState([
{ id: 1, label: "A" },
{ id: 2, label: "B" },
{ id: 3, label: "C" },
]);
<Sortable.Root items={items} onItemsChange={setItems}>
{items.map((item) => (
<Sortable.Item key={item.id} id={item.id}>
<div>{item.label}</div>
</Sortable.Item>
))}
</Sortable.Root>Orientation
The orientation property controls how items can be sorted. Sortable supports sorting in a vertical column, a horizontal row, or even across a grid.
A
B
C
E
F
G
H
I
J
const [items, setItems] = useState([
{ id: 1, label: "A" },
{ id: 2, label: "B" },
{ id: 3, label: "C" },
]);
<Sortable.Root orientation="horizontal" items={items} onItemsChange={setItems}>
<Stack orientation="horizontal" gap={4}>
{items.map((item) => (
<Sortable.Item key={item.id} id={item.id}>
<Box label={item.label} height="160px" width="80px" />
</Sortable.Item>
))}
</Stack>
</Sortable.Root>Drag handles
By default, the entire Sortable.Item is draggable. We can use Sortable.Handle to only allow certain parts of a sortable item to be dragged.
A
B
C
const [items, setItems] = useState([
{ id: 1, label: "A" },
{ id: 2, label: "B" },
{ id: 3, label: "C" },
]);
<Sortable.Root items={items} onItemsChange={setItems}>
{items.map((item) => (
<Sortable.Item key={item.id} id={item.id}>
<div>{item.label}</div>
</Sortable.Item>
))}
</Sortable.Root>Constraints
You can easily change dragging behavior via the constraints property.
A
B
C
const [items, setItems] = useState([
{ id: 1, label: "A" },
{ id: 2, label: "B" },
{ id: 3, label: "C" },
]);
<Sortable.Root items={items} onItemsChange={setItems}>
{items.map((item) => (
<Sortable.Item key={item.id} id={item.id}>
<div>{item.label}</div>
</Sortable.Item>
))}
</Sortable.Root>