Documentation menu
Sortable

Sortable lists

The sortable preset turns a list into a reorderable one without wiring draggables and droppables by hand. Wrap the list in a SortableScope and each item in a SortableItem.

You'll learn
  • How to make a single list reorderable.
  • Which layout strategy to pick for lists and grids.
  • How to apply the reported move to your own state.

Usage

A SortableScope takes the ordered itemIds and an onMove callback; each child is a SortableItem with a matching id.

sortable.dart
SortableScope(
  controller: controller,
  strategy: SortableStrategies.verticalList,
  itemIds: order, // List<DndId>
  onMove: _onMove,
  child: Column(
    children: [
      for (final id in order) SortableItem(id: id, child: CardTile(id)),
    ],
  ),
)

Strategies

Pick a SortableStrategies to match your layout:

  • verticalList — a stacked column of items.
  • horizontalList — a row of items, e.g. tabs or nav pills.
  • grid — a wrapping grid that reflows in two dimensions.
  • dropOnOver — lands the move on the item the drag is over, whatever the layout.

The first three resolve the target from the dragged rectangle's center, so a move commits once that center crosses a neighbour's. If your UI highlights the target or opens a gap, prefer dropOnOver so the drop lands where the highlight is — see the recipes.

Managing state

dnd_kit reports a move as from/to indices — you own the list and apply it. Reordering is a remove-then-insert on your data:

on_move.dart
void _onMove(SortableMoveDetails details) {
  setState(() {
    final id = order.removeAt(details.fromIndex);
    order.insert(details.toIndex, id);
  });
}