React Native Modal
react-native-modal is an enhanced and highly customizable modal component for React Native, extending the capabilities of the built-in `<Modal>` component. It offers smooth enter/exit animations, flexible APIs, and features such as a customizable backdrop (opacity, color, timing), listeners for animation completion, automatic resizing on device rotation, and swipe-to-close functionality. The current development focus is on version 14.x, with `14.0.0-rc.1` being the latest release candidate, introducing support for React Native 0.78 and above. Historically, releases have been somewhat irregular, often aligning with major React Native version updates. This library differentiates itself by providing a richer user experience with built-in animations and gestures, which the native `<Modal>` component lacks by default.
Common errors
-
The modal does not display correctly on Android. It either appears partially off-screen, becomes non-interactive, or fails to render entirely.
cause Often seen when `react-native-modal` is used alongside other libraries that manage views or gestures, like `ReorderableList` or `react-native-reanimated-carousel` on Android. This can stem from conflicts in view hierarchy or animation handling.fixAs a workaround, try conditionally hiding conflicting components (e.g., `Carousel`) when the modal is open. Ensure your root component is wrapped in `GestureHandlerRootView` if using `react-native-gesture-handler`. -
KeyboardAvoidingView not working properly inside the modal on Android or iOS, leading to inputs being obscured by the keyboard.
cause React Native's `KeyboardAvoidingView` can be inconsistent, especially within modals and across platforms, often due to issues with calculating offsets or conflicting layout behaviors.fixAdjust `keyboardVerticalOffset` prop for `KeyboardAvoidingView` based on platform (`Platform.OS === 'ios' ? 0 : 0`). For iOS modals with native headers, manual calculation involving `useSafeAreaInsets` might be needed. Alternatively, consider third-party keyboard-aware solutions. -
Modal is not showing up or toggling correctly, or requires a 'hot reload' (saving code) to appear after `isVisible` state changes.
cause `isVisible` prop not being properly controlled by component state, or sometimes race conditions in React Native's reconciliation, especially when conditionally mounting modals.fixEnsure `isVisible` is always controlled by a state variable (`useState`) and update it reliably. Avoid `&&` for conditional rendering; instead, always render the `<Modal>` component and control its visibility solely via `isVisible`. -
Swipe-to-close animation is not visible or swipe gestures are not working smoothly, especially when `useNativeDriver` is enabled for animations.
cause `useNativeDriver` might not support certain animation properties (e.g., `top` and `left` instead of `translateX`/`translateY`) used by the underlying animation library, or conflicts with other gesture handlers.fixEnsure `react-native-gesture-handler` is correctly linked and the root component is wrapped in `GestureHandlerRootView`. If using `useNativeDriver`, verify that the animation properties are compatible (prefer `transform` properties). Disable `useNativeDriver` if visual animations are crucial and it causes issues. -
Attempt to dismiss and immediately present another modal causes the app to freeze (iOS) or misbehaves when multiple modals are used consecutively.
cause React Native's native modal implementation can struggle with rapid, successive modal presentations/dismissals, as the native cleanup might be asynchronous, leading to conflicts if a new modal is triggered before the previous one fully unmounts.fixImplement a delay or use animation end listeners (`onModalHide`, `onModalWillHide`) to ensure one modal is fully dismissed before attempting to open another. Avoid imperative modal patterns that do not respect the component lifecycle.
Warnings
- breaking Version 14.x (currently in Release Candidate) bumps the minimum required React Native version to `0.78.0` and above. Projects on older React Native versions will need to upgrade or stick to v13.x.
- breaking Version 13.0.0 introduced a breaking change by removing the usage of the deprecated `removeListener` function, requiring `react-native>=0.65`.
- breaking Version 12.0.0 included a types update where `defaultProps` are now optional, which could affect TypeScript consumers.
- gotcha Version 14.0.0-rc.1 is a release candidate and is explicitly noted as 'untested on Expo'. It may have instabilities or unexpected behavior in Expo managed workflows.
- gotcha The project is actively seeking new maintainers and contributors. This could imply a slower development pace or potential changes in project direction if new maintainers take over.
Install
-
npm install react-native-modal -
yarn add react-native-modal -
pnpm add react-native-modal
Imports
- Modal
import { Modal } from 'react-native-modal';import Modal from 'react-native-modal';
- ModalProps
import type { ModalProps } from 'react-native-modal'; - Modal (CJS)
const Modal = require('react-native-modal');const Modal = require('react-native-modal').default;
Quickstart
import React, {useState} from 'react';
import {Button, Text, View, StyleSheet} from 'react-native';
import Modal from 'react-native-modal';
function ModalTester() {
const [isModalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
return (
<View style={styles.container}>
<Button title="Show modal" onPress={toggleModal} />
<Modal isVisible={isModalVisible}>
<View style={styles.modalContent}>
<Text style={styles.modalText}>Hello from the modal!</Text>
<Button title="Hide modal" onPress={toggleModal} />
</View>
</Modal>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalContent: {
backgroundColor: 'white',
padding: 22,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 4,
borderColor: 'rgba(0, 0, 0, 0.1)',
},
modalText: {
marginBottom: 15,
fontSize: 18,
},
});
export default ModalTester;