Reorderable List
Demonstrates a sortable list using DraxList — the simplest way to add drag-to-reorder.
Key Concepts
- DraxList — wraps FlatList with full reorder support
- Long-press to drag — 250ms default delay
- Auto-scroll — scrolls when dragging near edges
- Animation presets — items shift with smooth animations
Features Shown
| Feature | How |
|---|---|
DraxList | Convenience wrapper with data, keyExtractor, onReorder |
animationConfig | Animation preset for shift animations |
onReorder | Callback with new data order |
lockToMainAxis | Items stay on the vertical axis during drag |
Source Code
example/screens/reorderable-list.tsx
import { useState } from 'react';
import { StyleSheet, View, Text, Pressable } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { DraxProvider, DraxList } from 'react-native-drax';
import type { SortableAnimationPreset } from 'react-native-drax';
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const PRESETS: { key: SortableAnimationPreset; label: string }[] = [
{ key: 'default', label: 'Default' },
{ key: 'spring', label: 'Spring' },
{ key: 'gentle', label: 'Gentle' },
{ key: 'snappy', label: 'Snappy' },
{ key: 'none', label: 'None' },
];
const getBackgroundColor = (alphaIndex: number) => {
switch (alphaIndex % 6) {
case 0:
return '#ffaaaa';
case 1:
return '#aaffaa';
case 2:
return '#aaaaff';
case 3:
return '#ffffaa';
case 4:
return '#ffaaff';
case 5:
return '#aaffff';
default:
return '#aaaaaa';
}
};
const getHeight = (alphaIndex: number) => {
let height = 50;
if (alphaIndex % 2 === 0) {
height += 10;
}
if (alphaIndex % 3 === 0) {
height += 20;
}
return height;
};
const getItemStyleTweaks = (alphaItem: string) => {
const alphaIndex = alphabet.indexOf(alphaItem);
return {
backgroundColor: getBackgroundColor(alphaIndex),
height: getHeight(alphaIndex),
};
};
export default function ReorderableList() {
const [alphaData, setAlphaData] = useState(alphabet);
const [animPreset, setAnimPreset] =
useState<SortableAnimationPreset>('default');
const insets = useSafeAreaInsets();
return (
<DraxProvider>
<View
testID="reorderable-list-screen"
style={[
styles.container,
{
paddingTop: insets.top,
paddingLeft: insets.left,
paddingRight: insets.right,
},
]}
>
<View style={styles.presetBar}>
<Text style={styles.presetLabel}>Animation:</Text>
{PRESETS.map((p) => (
<Pressable
key={p.key}
testID={`preset-${p.key}`}
onPress={() => setAnimPreset(p.key)}
style={[
styles.presetButton,
animPreset === p.key && styles.presetButtonActive,
]}
>
<Text
style={[
styles.presetButtonText,
animPreset === p.key && styles.presetButtonTextActive,
]}
>
{p.label}
</Text>
</Pressable>
))}
</View>
<DraxList
data={alphaData}
keyExtractor={(item) => item}
animationConfig={animPreset}
inactiveItemStyle={{ opacity: 0.5 }}
containerStyle={styles.container}
style={styles.list}
containerDraxViewProps={{
testID: 'sortable-list-container',
accessibilityLabel: 'Reorderable list of letters A through Z',
}}
scrollEventThrottle={16}
onReorder={({ data, fromIndex, fromItem, toIndex, toItem }) => {
console.log(
`[reorderableList:onReorder] from=${fromIndex} (${fromItem}) to=${toIndex} (${toItem})`
);
setAlphaData(data);
}}
onDragStart={({ index, item }) => {
console.log(
`[reorderableList:onDragStart] index=${index} item=${item}`
);
}}
onDragPositionChange={({
index,
item,
toIndex,
previousIndex,
}) => {
console.log(
`[reorderableList:onDragPositionChange] index=${index} item=${item} toIndex=${toIndex} previousIndex=${previousIndex}`
);
}}
onDragEnd={({ index, item, toIndex, cancelled }) => {
console.log(
`[reorderableList:onDragEnd] index=${index} item=${item} toIndex=${toIndex} cancelled=${cancelled}`
);
}}
renderItem={({ item }) => (
<View
testID={`sortable-item-${item}`}
style={[styles.alphaItem, getItemStyleTweaks(item)]}
>
<Text style={styles.alphaText}>{item}</Text>
</View>
)}
/>
</View>
</DraxProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
list: {
flex: 1,
},
presetBar: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 6,
backgroundColor: '#f0f0f0',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#ddd',
},
presetLabel: {
fontSize: 13,
fontWeight: '600',
color: '#555',
marginRight: 6,
},
presetButton: {
paddingHorizontal: 10,
paddingVertical: 5,
borderRadius: 14,
backgroundColor: '#e0e0e0',
marginHorizontal: 3,
},
presetButtonActive: {
backgroundColor: '#3b82f6',
},
presetButtonText: {
fontSize: 12,
fontWeight: '500',
color: '#555',
},
presetButtonTextActive: {
color: '#fff',
},
alphaItem: {
backgroundColor: '#aaaaff',
borderRadius: 8,
margin: 4,
padding: 4,
justifyContent: 'center',
alignItems: 'center',
},
alphaText: {
fontSize: 28,
},
});
Related
- Sortable List Guide — Full tutorial
- Animation Presets Guide — Customize animations
- API: DraxList — Props reference