Skip to main content

Scrolling

Demonstrates drag from a scrollable container to a drop zone. The scroll view auto-scrolls when dragging near edges.

Key Concepts

  • DraxScrollView — scrollable container with auto-scroll
  • Drag from scroll — items inside a scroll view can be dragged out
  • Auto-scroll — scrolls when finger approaches edges during drag

Features Shown

FeatureHow
DraxScrollViewWraps the scrollable item list
Auto-scrollEdges trigger scroll during drag
External dropItems can be dropped outside the scroll

Source Code

▶️ Live demo · 💻 Source

example/screens/scrolling.tsx
import { useState } from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
DraxProvider,
DraxScrollView,
DraxView,
DraxSnapbackTargetPreset,
} from 'react-native-drax';

export default function Scrolling() {
const [sum, setSum] = useState(0);
const insets = useSafeAreaInsets();

return (
<DraxProvider>
<View testID="scrolling-screen" style={[styles.container, { paddingTop: insets.top, paddingLeft: insets.left, paddingRight: insets.right }]}>
<DraxScrollView horizontal style={styles.scrollView}>
<DraxView
testID="scroll-item-1"
accessibilityLabel="Draggable number 1"
accessibilityHint="Long press and drag to the sum bucket"
accessibilityRole="button"
style={[styles.item, styles.item1]}
dragPayload={1}
onDragStart={() => console.log('[scrolling:item1] dragStart')}
onDragEnd={() => console.log('[scrolling:item1] dragEnd')}
>
<Text style={styles.itemText}>1</Text>
</DraxView>
<DraxView
testID="scroll-item-2"
accessibilityLabel="Draggable number 2"
accessibilityHint="Long press and drag to the sum bucket"
accessibilityRole="button"
style={[styles.item, styles.item2]}
dragPayload={2}
onDragStart={() => console.log('[scrolling:item2] dragStart')}
onDragEnd={() => console.log('[scrolling:item2] dragEnd')}
>
<Text style={styles.itemText}>2</Text>
</DraxView>
<DraxView
testID="scroll-item-3"
accessibilityLabel="Draggable number 3"
accessibilityHint="Long press and drag to the sum bucket"
accessibilityRole="button"
style={[styles.item, styles.item3]}
dragPayload={3}
onDragStart={() => console.log('[scrolling:item3] dragStart')}
onDragEnd={() => console.log('[scrolling:item3] dragEnd')}
>
<Text style={styles.itemText}>3</Text>
</DraxView>
<DraxView
testID="scroll-item-4"
accessibilityLabel="Draggable number 4"
accessibilityHint="Long press and drag to the sum bucket"
accessibilityRole="button"
style={[styles.item, styles.item4]}
dragPayload={4}
onDragStart={() => console.log('[scrolling:item4] dragStart')}
onDragEnd={() => console.log('[scrolling:item4] dragEnd')}
>
<Text style={styles.itemText}>4</Text>
</DraxView>
</DraxScrollView>
<View style={styles.footer}>
<Text style={styles.description}>
The area above is a horizontal DraxScrollView containing 4 draggable
number items. The number items can be dragged into the sum bucket
below. Dragging an item near the edge of the scroll view will
auto-scroll.
</Text>
<DraxView
testID="sum-bucket"
accessibilityLabel={`Sum bucket, current value: ${sum}`}
accessibilityHint="Drop number items here to add to the sum"
style={styles.bucket}
receivingStyle={styles.bucketReceiving}
onReceiveDragDrop={(event) => {
const payload = event.dragged.payload;
console.log(`[scrolling:bucket] receiveDragDrop payload=${payload}`);
if (typeof payload === 'number') {
setSum((s) => s + payload);
}
return DraxSnapbackTargetPreset.None;
}}
>
<Text style={styles.itemText}>{`Sum: ${sum}`}</Text>
</DraxView>
</View>
</View>
</DraxProvider>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
},
scrollView: {
flex: 1,
},
item: {
padding: 12,
margin: 24,
borderRadius: 10,
borderWidth: 2,
borderColor: '#606060',
justifyContent: 'center',
alignItems: 'center',
},
item1: {
width: 200,
height: 100,
backgroundColor: '#8080ff',
},
item2: {
width: 100,
height: 250,
marginTop: 50,
backgroundColor: '#80ff80',
},
item3: {
width: 120,
height: 120,
marginTop: 120,
backgroundColor: '#ff8080',
},
item4: {
width: 80,
height: 120,
marginLeft: 80,
backgroundColor: '#ff80ff',
},
itemText: {
fontSize: 32,
},
footer: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
borderTopColor: '#d0d0d0',
borderTopWidth: 1,
padding: 20,
},
description: {
fontSize: 16,
fontStyle: 'italic',
marginBottom: 20,
},
bucket: {
width: 180,
height: 120,
backgroundColor: '#d0d0d0',
borderColor: '#000000',
borderWidth: 3,
borderRadius: 4,
justifyContent: 'center',
alignItems: 'center',
},
bucketReceiving: {
backgroundColor: '#ffffd0',
},
});