useDragToReorder
Pre-alphaThe registry and the CLI are not published yet.Roadmap

useDragToReorder

Lift a row and drag it to a new position in a list.

Draft

The API shown here is conceptual and may change.

The hook behind Drag-to-reorder. That page explains how the drag starts, the target slot, auto-scroll, the drop and accessibility. This one covers the API.

Installation

npx axiom add use-drag-to-reorder
pnpm dlx axiom add use-drag-to-reorder
yarn dlx axiom add use-drag-to-reorder
bun x axiom add use-drag-to-reorder

Installs: react-native-reanimated, react-native-gesture-handler.

Usage

The hook owns the gesture state. ReorderableRow moves each row, DragHandle starts the drag.

Conceptual
import {
	useDragToReorder,
	ReorderableRow,
	DragHandle,
} from "@/hooks/use-drag-to-reorder";

function Queue() {
	const [tracks, setTracks] = useState(initialTracks);

	const reorder = useDragToReorder({
		data: tracks,
		keyExtractor: (track) => track.id,
		onReorder: (from, to) => setTracks((list) => move(list, from, to)),
	});

	return (
		<Animated.ScrollView {...reorder.scrollProps}>
			{tracks.map((track, index) => (
				<ReorderableRow key={track.id} control={reorder} index={index}>
					<Item trailing={<DragHandle control={reorder} index={index} />}>

					</Item>
				</ReorderableRow>
			))}
		</Animated.ScrollView>
	);
}

move returns a new array with the item at from moved to to. The hook ships one:

export const move = <T>(list: T[], from: number, to: number) => {
	const next = [...list];
	next.splice(to, 0, next.splice(from, 1)[0]);
	return next;
};

Without handles

Drop DragHandle and set trigger: 'longPress'. The whole row starts the drag after longPressDelay, and a tap still reaches the row’s onPress.

Conceptual
const reorder = useDragToReorder({
	data,
	keyExtractor,
	onReorder,
	trigger: "longPress",
});

Saving the order

onReorder runs once per drop. Update local state there, and send the new order to the server from it or after a debounce; if the request fails, restore the previous array.

Options

OptionTypeDefaultDescription
dataT[]Items in their current order.
keyExtractor(item: T) => stringStable key, used to keep measurements across re-renders.
onReorder(from: number, to: number) => voidCalled on drop when the position changed.
trigger'handle' | 'longPress''handle'What starts the drag.
longPressDelaynumber300Delay in ms with trigger: 'longPress'.
autoScrollEdgenumber60Distance in pt from the list’s edges where auto-scroll starts.
autoScrollSpeednumber600Maximum auto-scroll speed in pt/s, at the very edge.
onDragStart / onDragEnd(index: number) => voidCalled when a row lifts and when it’s dropped. Default: a light haptic on start.
enabledbooleantrueTurns reordering off.

Return value

KeyTypeDescription
activeIndexSharedValue<number>Index of the lifted row, -1 when idle.
targetIndexSharedValue<number>Slot the row would drop into.
translateYSharedValue<number>Offset of the lifted row from its slot, in pt.
draggingbooleantrue while a row is lifted. React state.
moveItem(from: number, to: number) => voidMoves without a gesture, for the accessibility actions. Calls onReorder.
scrollPropsobjectRef, scroll handler and native gesture, for an Animated.ScrollView or Animated.FlatList.