Sortable List
DraxList is the fastest way to add drag-to-reorder to a list. It wraps any list component (FlatList, FlashList, LegendList) with full reorder support.
Basic Usage
import { useState } from 'react';
import { Text, View } from 'react-native';
import { DraxProvider, DraxList } from 'react-native-drax';
function App() {
const [items, setItems] = useState(['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']);
return (
<DraxProvider>
<DraxList
data={items}
keyExtractor={(item) => item}
onReorder={({ data }) => setItems(data)}
renderItem={({ item }) => (
<View style={{ padding: 16, backgroundColor: '#f5f5f5', marginVertical: 2 }}>
<Text>{item}</Text>
</View>
)}
/>
</DraxProvider>
);
}
Long-press any item to start dragging. Items shift to make room. Release to drop.
Using with FlashList
Pass any list component via the component prop:
import { FlashList } from '@shopify/flash-list';
<DraxList
component={FlashList}
data={items}
keyExtractor={(item) => item.id}
onReorder={({ data }) => setItems(data)}
renderItem={({ item }) => <ItemCard item={item} />}
estimatedItemSize={60}
/>
Extra props like estimatedItemSize are forwarded to the underlying list component.
Reorder Event
The onReorder callback receives detailed information:
<DraxList
onReorder={({ data, fromIndex, toIndex, fromItem, toItem }) => {
console.log(`Moved "${fromItem}" from ${fromIndex} to ${toIndex}`);
setItems(data); // The new ordered array
}}
/>
| Field | Type | Description |
|---|---|---|
data | T[] | The reordered array |
fromIndex | number | Original position |
toIndex | number | New position |
fromItem | T | The moved item |
toItem | T | The item displaced |
isExternalDrag | boolean | Whether the drag came from outside this list |
Data Ownership
Drax commits reorders internally. onReorder is a notification — you update your state, and when Drax detects the data matches what it already committed, it skips re-rendering (no double render).
Reorder Strategies
Two strategies for how items rearrange:
<DraxList reorderStrategy="insert" /> {/* Default: items shift to fill the gap */}
<DraxList reorderStrategy="swap" /> {/* Items swap positions directly */}
Horizontal Lists
<DraxList
horizontal
data={items}
keyExtractor={(item) => item}
onReorder={({ data }) => setItems(data)}
renderItem={({ item }) => (
<View style={{ padding: 16, margin: 4, backgroundColor: '#eee' }}>
<Text>{item}</Text>
</View>
)}
/>
Drag Lifecycle Callbacks
Track the full drag lifecycle:
<DraxList
data={items}
keyExtractor={(item) => item}
onReorder={({ data }) => setItems(data)}
onDragStart={({ index, item }) => {
console.log(`Started dragging "${item}" at index ${index}`);
}}
onDragPositionChange={({ index, toIndex, previousIndex }) => {
console.log(`Position changed: ${previousIndex} → ${toIndex}`);
}}
onDragEnd={({ index, toIndex, cancelled }) => {
console.log(`Drag ended at ${toIndex}, cancelled: ${cancelled}`);
}}
renderItem={({ item }) => <ItemCard item={item} />}
/>
Styling the Container
<DraxList
containerStyle={{ flex: 1, padding: 8 }} {/* Style the DraxView wrapper */}
style={{ paddingVertical: 4 }} {/* Style the list itself */}
itemDraxViewProps={{ {/* Props for each item's DraxView */}
hoverStyle: { opacity: 0.8, transform: [{ scale: 1.05 }] },
}}
/>
Lock to Main Axis
Prevent items from drifting sideways during vertical reorder:
<DraxList lockToMainAxis />
Next Steps
- Sortable Grid — Multi-column layout
- Composable API — Full control with useSortableList
- Animation Presets — Spring, gentle, snappy