Why Modalize for Scrolling Modals?
Modals are an essential component of mobile app development. They provide a way to display content that overlays the main application interface, perfect for presenting additional information, forms, or actions without navigating away from the current screen.
While React Native provides a basic Modal component, developers often need more flexibility, particularly when dealing with scrolling content that needs to handle keyboard interactions gracefully. Modalize is specifically designed to address these pain points.
Modalize is described as "a highly customizable modal/bottom sheet that loves scrolling content" and is built with react-native-gesture-handler to address common issues with scrolling, swiping, and keyboard behaviors. For teams building React Native applications, Modalize provides the foundation for creating polished, professional modal experiences that users expect in modern mobile apps.
Everything you need to build professional modal experiences
Native Scrolling Support
Designed from the ground up to handle scrollable content without the complications of the built-in Modal component
Gesture-Based Interaction
Built with react-native-gesture-handler for smooth swipe-to-dismiss and drag interactions
Smart Keyboard Handling
Automatic keyboard avoidance and position adjustments for form inputs and text fields
Fully Customizable
Full control over appearance including handles, overlays, snap points, and animation behaviors
List Performance
Optimized FlatList integration for displaying large datasets within modals without performance issues
Bottom Sheet Mode
First-class support for bottom sheet patterns that users expect in modern mobile apps
Getting Started with Modalize
Installation and Dependencies
To use Modalize in your React Native project, install the package along with its peer dependency:
npm install react-native-modalize
# or
yarn add react-native-modalize
Modalize is built with react-native-gesture-handler to address common issues with scrolling, swiping, and keyboard behaviors. Make sure to properly configure react-native-gesture-handler in your project by following the official installation guide.
Basic Usage
The simplest implementation of Modalize involves wrapping your content and controlling visibility through state:
import { useRef } from 'react';
import { Modalize } from 'react-native-modalize';
const MyComponent = () => {
const modalRef = useRef(null);
const openModal = () => {
modalRef.current?.open();
};
const closeModal = () => {
modalRef.current?.close();
};
return (
<>
<Button title="Open Modal" onPress={openModal} />
<Modalize ref={modalRef}>
<View style={{ padding: 20 }}>
<Text>Your modal content goes here</Text>
</View>
</Modalize>
</>
);
};
The ref-based API gives you programmatic control over the modal's state while maintaining clean component logic.
Core Props and Configuration
Modalize provides a rich set of props that control the modal's behavior and appearance. Understanding these props is key to building the exact modal experience you need.
Essential Props
Visibility and Height Control:
alwaysOpen- Sets a default open height when the modal is opened, useful for showing a peek of contentadjustToContentHeight- Automatically adjusts modal height to fit the content within
Content Rendering:
withScrollView- Wraps children in a ScrollView for scrolling contentchildren- The content to display within the modalFlatListProps- Props for rendering lists within the modal with optimized performanceHeaderComponent- A fixed header that sits above the scrollable contentFooterComponent- A fixed footer that sits below the scrollable content
Keyboard Handling:
keyboardAvoidingBehavior- How the modal handles keyboard appearance (padding, position, or none)keyboardAvoidingOffset- Offset for keyboard avoidance calculations
Customizing Appearance
The modal's visual appearance can be customized through:
<Modalize
modalStyle={styles.modal}
handleStyle={styles.handle}
handlePosition="center"
overlayStyle={styles.overlay}
closeSnapBackStraight={true}
>
{content}
</Modalize>
modalStyle- Custom styles for the modal containerhandleStyle- Custom styles for the drag handlehandlePosition- Position of the handle ("center" or "outside")overlayStyle- Custom styles for the overlay backgroundcloseSnapBackStraight- Whether the modal closes with a straight snap animation
These customization options make Modalize an excellent choice for building consistent UI components across your React Native application.
Creating Scrolling Content Modals
The primary strength of Modalize is its excellent handling of scrolling content. Let's explore the different approaches for creating scrollable modals.
The withScrollView Prop
When your modal content exceeds the available screen height, enable scrolling with the withScrollView prop:
<Modalize
withScrollView={true}
showsVerticalScrollIndicator={true}
scrollEnabled={true}
>
<View>
<Text>Header Content</Text>
{/* Long content that needs scrolling */}
<View style={{ height: 1000 }}>
<Text>Scrollable content here</Text>
</View>
</View>
</Modalize>
Best Practices for Scrollable Content:
- Structure your content with a fixed header section followed by scrollable content
- Avoid mixing fixed and scrollable content without proper layout separation
- Use
contentContainerStyleto customize the scroll view's inner layout
Handling Dynamic Content Height
When content height changes dynamically, combine alwaysOpen with adjustToContentHeight:
<Modalize
alwaysOpen={100}
adjustToContentHeight={true}
>
{dynamicContent}
</Modalize>
Important Note: There is a known issue where ScrollView doesn't work correctly when combined with adjustToContentHeight. If you encounter this, consider using:
- A fixed
alwaysOpenvalue instead - FlatListProps for displaying large lists
FlatList Integration
For modals that display lists, use FlatListProps for optimal performance:
<Modalize
flatListProps={{
data: items,
renderItem: ({ item }) => <ListItem item={item} />,
keyExtractor: item => item.id,
showsVerticalScrollIndicator: false,
// Additional FlatList props...
}}
/>
Using FlatListProps is preferred over wrapping content in ScrollView because it provides:
- Virtualized rendering for better memory efficiency
- Built-in scroll indicator configuration
- Native refresh control integration
- Optimized item recycling
Keyboard Handling and Best Practices
One of the most challenging aspects of modal development is handling the keyboard gracefully. Modalize provides built-in support for keyboard avoidance, but you may need to fine-tune the behavior for your specific use case.
Keyboard Avoidance Configuration
<Modalize
keyboardAvoidingBehavior="padding"
keyboardAvoidingOffset={100}
>
{content}
</Modalize>
keyboardAvoidingBehavior Options:
"padding"- Adds padding to avoid the keyboard (recommended for most cases)"position"- Changes the modal's position relative to the keyboard"none"- Disables automatic keyboard avoidance
Form Implementation Patterns
When building forms within modals, follow these patterns for the best user experience:
<Modalize
alwaysOpen={300}
keyboardAvoidingBehavior="padding"
>
<View style={{ padding: 16 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Contact Form</Text>
<TextInput
placeholder="Your Name"
style={{ height: 50, borderWidth: 1, marginTop: 16 }}
onFocus={() => modalRef.current?.snapTo(1)}
/>
<TextInput
placeholder="Email Address"
keyboardType="email-address"
style={{ height: 50, borderWidth: 1, marginTop: 8 }}
/>
<TextInput
placeholder="Message"
multiline
numberOfLines={4}
style={{ height: 100, borderWidth: 1, marginTop: 8 }}
/>
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 16,
borderRadius: 8,
marginTop: 16
}}
onPress={handleSubmit}
>
<Text style={{ color: 'white', textAlign: 'center' }}>Submit</Text>
</TouchableOpacity>
</View>
</Modalize>
Form Best Practices:
- Use
alwaysOpento prevent the modal from resizing during typing - Position important form fields above the keyboard
- Handle focus events to adjust modal position if needed
- Consider using
keyboardVerticalOffsetfor precise positioning on iOS
Advanced Customization
Modalize offers extensive customization options for creating unique modal experiences that match your app's design language.
Snap Points and Drag Behavior
Control how the modal responds to drag gestures:
<Modalize
snapPoint={400}
panGestureEnabled={true}
panGestureComponentEnabled={true}
closeSnapBackStraight={true}
>
{content}
</Modalize>
Gesture Configuration Options:
snapPoint- The height the modal snaps to when openedpanGestureEnabled- Enable or disable pan gestures for closingpanGestureComponentEnabled- Enable or disable the drag handle componentcloseSnapBackStraight- Whether the modal closes with a straight snap animation
Custom Header and Footer
Add fixed headers and footers to your modal:
<Modalize
HeaderComponent={
<View style={{ padding: 20, borderBottomWidth: 1 }}>
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>Modal Title</Text>
</View>
}
FooterComponent={
<View style={{ padding: 20, borderTopWidth: 1 }}>
<Button title="Done" onPress={closeModal} />
</View>
}
>
{scrollableContent}
</Modalize>
Complete Example: Profile Modal
import { useRef } from 'react';
import { Modalize } from 'react-native-modalize';
import { Image, View, Text, TextInput, TouchableOpacity, StyleSheet } from 'react-native';
const ProfileModal = ({ visible, onClose }) => {
const modalRef = useRef(null);
React.useEffect(() => {
if (visible) {
modalRef.current?.open();
} else {
modalRef.current?.close();
}
}, [visible]);
return (
<Modalize
ref={modalRef}
onClosed={onClose}
alwaysOpen={400}
modalStyle={styles.modal}
handleStyle={styles.handle}
keyboardAvoidingBehavior="padding"
>
<View style={styles.content}>
<View style={styles.avatarContainer}>
<Image
source={{ uri: 'https://example.com/avatar.jpg' }}
style={styles.avatar}
/>
<TouchableOpacity style={styles.changePhotoButton}>
<Text style={styles.changePhotoText}>Change Photo</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Full Name"
style={styles.input}
defaultValue="John Doe"
/>
<TextInput
placeholder="Email"
keyboardType="email-address"
style={styles.input}
defaultValue="[email protected]"
/>
<TextInput
placeholder="Bio"
multiline
numberOfLines={3}
style={{...styles.input, height: 80}}
/>
</View>
</Modalize>
);
};
const styles = StyleSheet.create({
modal: {
backgroundColor: '#fff',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
handle: {
backgroundColor: '#ccc',
width: 40,
height: 4,
borderRadius: 2,
},
content: {
padding: 20,
},
avatarContainer: {
alignItems: 'center',
marginBottom: 20,
},
avatar: {
width: 80,
height: 80,
borderRadius: 40,
marginBottom: 10,
},
input: {
height: 50,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
paddingHorizontal: 15,
marginBottom: 12,
},
});
Common Issues and Solutions
When working with Modalize, you may encounter some common challenges. Here are solutions to the most frequently reported issues.
ScrollView Not Working with adjustToContentHeight
There is a known issue where ScrollView doesn't work correctly when combined with adjustToContentHeight. The modal may not scroll even when content overflows.
Solutions:
- Use
alwaysOpenwith a fixed height value instead - Use
FlatListPropsinstead of wrapping content in ScrollView - Force re-render by adding a key to the children when content changes
Cannot Scroll FlatList Inside Modalize
If your FlatList inside Modalize isn't scrolling properly:
// Problem: FlatList wrapped in children
<Modalize>
<FlatList
data={items}
renderItem={renderItem}
/>
</Modalize>
// Solution: Use flatListProps instead
<Modalize
flatListProps={{
data: items,
renderItem: renderItem,
keyExtractor: item => item.id,
showsVerticalScrollIndicator: true,
scrollEnabled: true,
}}
/>
Height Calculation Issues
When using alwaysOpen with adjustToContentHeight, the modal may not expand properly if the content height changes dynamically.
Solution: Use a key to force re-render when content changes:
<Modalize
alwaysOpen={100}
adjustToContentHeight={true}
>
<View key={contentVersion}>
{dynamicContent}
</View>
</Modalize>
Keyboard Covers Form Fields
If the keyboard still covers form fields despite keyboard avoidance:
<Modalize
keyboardAvoidingBehavior="padding"
keyboardAvoidingOffset={Platform.OS === 'ios' ? 120 : 100}
>
<ScrollView keyboardShouldPersistTaps="handled">
{formContent}
</ScrollView>
</Modalize>
Modal Doesn't Close on Background Tap
Ensure the overlay is configured correctly:
<Modalize
overlay={true}
overlayStyle={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
onOverlayPress={closeModal}
>
{content}
</Modalize>
| Feature | React Native Modal | Modalize |
|---|---|---|
| Scrolling Content | Limited, requires workarounds | Native support designed from the ground up |
| Gesture Handling | Basic tap to dismiss | Advanced swipe, drag, and pan gestures |
| Keyboard Avoidance | Manual implementation required | Automatic with configurable behavior |
| Customization | Limited to basic styling | Full control over appearance and behavior |
| Bottom Sheet Mode | Not supported | First-class support with snap points |
| Performance | Native implementation | Optimized for lists with FlatListProps |
| Animation Options | Basic fade/slide | Rich animation configuration |
Conclusion
Modalize provides a robust solution for creating custom scrolling modals in React Native. Its focus on scrollable content, combined with excellent gesture support and keyboard handling, makes it an excellent choice for displaying:
- Forms - Login, registration, contact forms with keyboard handling
- Lists - Selection lists, settings panels, search results
- Detail Views - Product details, user profiles, content previews
- Actions Sheets - Confirmation dialogs, option selections
Key Takeaways:
- Use
withScrollViewfor general scrolling content needs - Prefer
FlatListPropsfor displaying large lists within modals - Configure
alwaysOpento show content preview when the modal first appears - Use
keyboardAvoidingBehaviorto ensure form fields remain accessible - Customize appearance through
modalStyle,handleStyle, andoverlayStyle
When choosing Modalize for your project, consider your specific needs:
- For simple modals with minimal scrolling, the built-in React Native Modal may suffice
- For bottom sheet patterns and advanced gestures, Modalize is an excellent choice
- For maximum customization and control, Modalize provides the flexibility you need
By following the patterns and best practices outlined in this guide, you can create professional, accessible modal experiences that delight your users and enhance your app's usability. Our web development team specializes in building React Native applications with sophisticated UI components like Modalize that elevate the user experience.