Overview
When building sortable interfaces, you need to keep your application state in sync with drag operations. There are two approaches:- Using the
movehelper from@dnd-kit/helpers— a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box. This is covered in the Multiple sortable lists guide. - Manual state management — using the sortable properties and type guards for full control over state updates.
source and target behave during drag operations.
Understanding optimistic sorting
TheOptimisticSortingPlugin is enabled by default for all sortable items. It optimistically reorders DOM elements during a drag so the UI feels responsive without requiring React re-renders on every dragover event.
A key consequence is that source and target in the drag operation will refer to the same element during a drag. This means you cannot compare source.id and target.id to determine what moved.
Instead, use the sortable-specific properties on the source:
These properties are available on the
source when it is a sortable element. Use the isSortable type guard to narrow the type.Single list without the move helper
With optimistic sorting, you only need to handleonDragEnd. The OptimisticSortingPlugin takes care of visual feedback during the drag.
Multiple lists without the move helper
For multiple lists, useinitialGroup and group to detect whether the item stayed in the same list or moved to a different one:
When updating state in
onDragOver (rather than onDragEnd), save a snapshot in onDragStart so you can revert if the drag is canceled.Comparison with the move helper
Use the
move helper when your data structure matches its expectations (flat arrays or Record<string, array>). Use manual state management when you need more control, have custom data structures, or use computed IDs.
Type guards
isSortable
Checks whether a Draggable or Droppable is a sortable instance, narrowing the type to expose index, initialIndex, group, and initialGroup:
isSortableOperation
Narrows both source and target of a drag operation at once: