Skip to main content

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
}}
/>
FieldTypeDescription
dataT[]The reordered array
fromIndexnumberOriginal position
toIndexnumberNew position
fromItemTThe moved item
toItemTThe item displaced
isExternalDragbooleanWhether 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