Fix React Native Modal ScrollView Not Scrolling (Best Modal Pattern)
Fix React Native Modal ScrollView Not Scrolling (Best Modal Pattern)
A common issue when building modals in React Native is that a
ScrollView inside a Modal appears scrollable but
does not actually scroll smoothly. The scrollbar may appear, but gestures
don't move the content properly.
This usually happens because the modal overlay is intercepting touch events.
If the overlay is implemented using TouchableOpacity or
Pressable wrapped around the modal content, it can capture
scroll gestures before they reach the ScrollView.
In this post, we'll look at the problem and the correct modal pattern used in production React Native apps.
The Problem
Many developers structure their modal like this:
<TouchableOpacity style={styles.overlay} onPress={onClose}>
<TouchableOpacity style={styles.modal}>
<ScrollView>
...
</ScrollView>
</TouchableOpacity>
</TouchableOpacity>
The outer TouchableOpacity captures gestures meant for the
ScrollView. When the user tries to scroll, the overlay touch
handler blocks the gesture.
Result: The scrollbar appears, but scrolling feels stuck or doesn't work.
The Correct Modal Pattern
The correct solution is to separate the overlay press area from the modal content instead of wrapping everything inside one touchable.
Use a background press layer to close the modal while keeping the modal content completely independent.
<Modal
visible={visible}
transparent
animationType="fade"
onRequestClose={onClose}
>
<View style={styles.overlay}>
{/* Background close layer */}
<Pressable
style={StyleSheet.absoluteFill}
onPress={onClose}
/>
{/* Modal content */}
<View style={styles.modal}>
<View style={styles.header}>
<Text>Modal Title</Text>
</View>
<ScrollView
showsVerticalScrollIndicator
nestedScrollEnabled
>
<Text>
Long content goes here...
</Text>
</ScrollView>
<View style={styles.footer}>
<Text>Footer</Text>
</View>
</View>
</View>
</Modal>
Recommended Styles
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center'
},
modal: {
width: '90%',
maxHeight: '80%',
backgroundColor: 'white',
borderRadius: 12,
overflow: 'hidden'
}
The key detail here is the maxHeight. Without it, the
ScrollView might expand instead of scrolling.
Why This Pattern Works
Instead of nesting touchable elements like this:
TouchableOpacity (overlay)
└ Modal Content
└ ScrollView
We use a layered approach:
Overlay View
├ Pressable (background close)
└ Modal Content
└ ScrollView
This ensures the ScrollView receives gesture events directly,
allowing smooth scrolling inside the modal.
Extra Scroll Improvements
You can also improve the scroll experience with:
<ScrollView
showsVerticalScrollIndicator
nestedScrollEnabled
keyboardShouldPersistTaps="handled"
bounces={true}
/>
These options help especially when the modal contains forms or dynamic content.
Final Thoughts
If your modal contains long text, lists, or dynamic content, using the correct overlay pattern is essential. Avoid wrapping your entire modal inside a touchable component, as it often leads to gesture conflicts.
By separating the background press area from the modal content, you ensure that scrolling works correctly while still allowing users to tap outside the modal to close it.
This simple pattern will save you hours of debugging when building scrollable modals in React Native.
❤️ Support This Blog
If this post helped you, you can support my writing with a small donation. Thank you for reading.
Comments
Post a Comment