Overview
When using gestures with scrollable content, you need to coordinate between scroll gestures and navigation gestures. react-native-screen-transitions provides transition-aware scrollable components that handle this coordination automatically.
Transition-Aware Components
Use these components instead of standard React Native scrollables:
import Transition from "react-native-screen-transitions" ;
// ScrollView
< Transition.ScrollView >
{ /* content */ }
</ Transition.ScrollView >
// FlatList
< Transition.FlatList
data = { items }
renderItem = { ({ item }) => < Item data = { item } /> }
/>
These components accept all the same props as their React Native counterparts.
The navigation gesture behavior depends on the gestureDirection and scroll position:
Vertical Gestures
vertical (swipe down to dismiss)
At top of scroll : Navigation gesture activates (dismiss/snap)
Scrolled into content : Normal scroll behavior
At bottom : Only scroll behavior
< Stack.Screen
name = "Sheet"
options = { {
gestureEnabled: true ,
gestureDirection: "vertical" ,
... Transition . Presets . SlideFromBottom (),
} }
/>
Example : Bottom sheet that dismisses when swiping down from the top.
vertical-inverted (swipe up to dismiss)
At bottom of scroll : Navigation gesture activates
Scrolled into content : Normal scroll behavior
At top : Only scroll behavior
< Stack.Screen
name = "TopSheet"
options = { {
gestureEnabled: true ,
gestureDirection: "vertical-inverted" ,
... Transition . Presets . SlideFromTop (),
} }
/>
Example : Top sheet that dismisses when swiping up from the bottom.
Horizontal Gestures
horizontal / horizontal-inverted
At left/right edge : Navigation gesture activates
Scrolled into content : Normal scroll behavior
< Stack.Screen
name = "Detail"
options = { {
gestureEnabled: true ,
gestureDirection: "horizontal" ,
} }
/>
Example : Standard iOS-style back gesture from left edge.
Boundary Behavior
When the user reaches a scroll boundary (top/bottom/edge), the gesture system automatically coordinates between scrolling and navigation.
Default Behavior
import { View } from "react-native" ;
import Transition from "react-native-screen-transitions" ;
function BottomSheet () {
return (
< View style = { { flex: 1 } } >
< View style = { { padding: 20 } } >
< Text > Header (deadspace) </ Text >
</ View >
< Transition.ScrollView >
< Text > Scrollable content... </ Text >
{ /* Long content */ }
</ Transition.ScrollView >
</ View >
);
}
Swipe down at top : Dismisses or collapses snap point
Swipe up in deadspace : Expands to next snap point (if snap points enabled)
Swipe within scroll : Normal scroll behavior
Deadspace refers to non-scrollable areas like headers or footers outside the ScrollView.
With snap points enabled, ScrollView gestures can control snap expansion/collapse:
< Stack.Screen
name = "Sheet"
options = { {
gestureEnabled: true ,
gestureDirection: "vertical" ,
snapPoints: [ 0.5 , 1 ],
expandViaScrollView: true , // default
... Transition . Presets . SlideFromBottom (),
} }
/>
The expandViaScrollView option controls snap behavior at scroll boundaries:
expandViaScrollView: true (default)
expandViaScrollView: false
options = {{
snapPoints : [ 0.5 , 1 ],
expandViaScrollView : true ,
}}
// Behavior:
// - At top boundary: Swipe up expands, swipe down collapses/dismisses
// - In content: Normal scroll
When expandViaScrollView: false, users can only expand the sheet by swiping in deadspace areas (outside the ScrollView) or via programmatic control with snapTo().
Complete example showing proper ScrollView integration:
import { View , Text } from "react-native" ;
import Transition from "react-native-screen-transitions" ;
export default function BottomSheetScreen () {
return (
< View style = { { flex: 1 , backgroundColor: "white" } } >
{ /* Header - Deadspace */ }
< View style = { { padding: 20 , borderBottomWidth: 1 , borderColor: "#ccc" } } >
< View
style = { {
width: 40 ,
height: 4 ,
backgroundColor: "#ccc" ,
borderRadius: 2 ,
alignSelf: "center" ,
marginBottom: 10 ,
} }
/>
< Text style = { { fontSize: 20 , fontWeight: "bold" } } > Details </ Text >
</ View >
{ /* Scrollable Content */ }
< Transition.ScrollView style = { { flex: 1 } } >
< View style = { { padding: 20 } } >
{ Array . from ({ length: 50 }). map (( _ , i ) => (
< Text key = { i } style = { { marginVertical: 10 } } >
Item { i + 1 }
</ Text >
)) }
</ View >
</ Transition.ScrollView >
</ View >
);
}
// Layout configuration
< Stack.Screen
name = "bottomSheet"
options = { {
gestureEnabled: true ,
gestureDirection: "vertical" ,
snapPoints: [ 0.5 , 1 ],
initialSnapIndex: 0 ,
backdropBehavior: "dismiss" ,
expandViaScrollView: true ,
... Transition . Presets . SlideFromBottom (),
} }
/>
FlatList Support
FlatList works the same way as ScrollView:
import Transition from "react-native-screen-transitions" ;
function ListScreen () {
const data = Array . from ({ length: 100 }, ( _ , i ) => ({ id: i , title: `Item ${ i } ` }));
return (
< Transition.FlatList
data = { data }
renderItem = { ({ item }) => (
< View style = { { padding: 20 } } >
< Text > { item . title } </ Text >
</ View >
) }
keyExtractor = { ( item ) => item . id . toString () }
/>
);
}
Both Transition.ScrollView and Transition.FlatList support all standard props including ref, onScroll, contentContainerStyle, etc.
Gestures - Complete gesture configuration guide
Snap Points - Multi-stop sheet behavior
Presets - Built-in gesture-enabled transitions