Note: This documentation is in active development — content may be incomplete
Sortable
Overview
Sortable is a layout component that enables drag-and-drop reordering of items. It supports items arranged as vertical lists, horizontal rows, or grids.
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>Usage Guidelines
- Use sorting for meaningful order: Use a sortable layout when item order should be user-defined and affects priority, sequence, or organization.
- Use drag handles when needed: Use
Sortable.Handlewhen items contain other interactive controls or when a smaller drag target provides a clearer affordance. - Keep items easy to identify: Make sortable items distinct and scannable so users can track what they are moving.
API Reference
Sortable.Root
Provides drag-and-drop context and ordering logic for sortable items.
| Prop | Type | Default |
|---|---|---|
items | Array<{ id: string | number }> | - |
onItemsChange | (items: Array<{ id: string | number }>) => void | - |
children | ReactNode | - |
orientation | "vertical" | "horizontal" | "free" | "vertical" |
constrainToParent | boolean | true |
Sortable.Item
Registers an item in the sortable context and applies drag state.
| Prop | Type | Default |
|---|---|---|
id | string | number | - |
children | ReactNode | - |
className | string | - |
style | CSSProperties | - |
render | RenderProp<{ dragging: boolean }> | - |
Sortable.Handle
Optional drag handle that limits dragging to a specific child element.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | - |
className | string | - |
render | RenderProp | - |
Examples
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. 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}>
<Sortable.Handle />
<div>{item.label}</div>
</Sortable.Item>
))}
</Sortable.Root>Constraints
Items can be dragged beyond the parent's boundary by disabling the constrainToParent property.
A
B
C
const [items, setItems] = useState([
{ id: 1, label: "A" },
{ id: 2, label: "B" },
{ id: 3, label: "C" },
]);
<Sortable.Root constrainToParent={false} items={items} onItemsChange={setItems}>
{items.map((item) => (
<Sortable.Item key={item.id} id={item.id}>
<div>{item.label}</div>
</Sortable.Item>
))}
</Sortable.Root>