Introduction to React Native Multiple Modals
mainModal component and bottom tab navigation.repository·main·Indexed 41 days ago
https://github.com/paufau/react-native-multiple-modalsA native layering library for React Native version 3.5.0 that enables displaying multiple modals, sheets, and overlays simultaneously. It provides native performance and accessibility (WCAG) support, allowing overlays to appear above default native Modals and bottom tab navigation. Key features include the ModalView component, focus trapping via useFocusTrap, and stack management with useModalStack.
Modal component and bottom tab navigation.The library provides several advanced layering and UX capabilities:
Modal and above bottom tab navigation.The stacking order of ModalView instances is determined by the order in which they were opened, rather than their order in the JSX markup.
ModalView mounts, it is placed on top of all currently open modals.onRequestDismiss callback of the topmost modal.Compared to standard React Native or JS-based modal libraries, react-native-multiple-modals (via ModalView) provides a native implementation that allows for stacking multiple modals simultaneously.
Key technical differences:
UIWindow on iOS, Dialog on Android, and portals on Web) rather than JS-based portals.Modal (which cannot stack on iOS) or react-native-modal, ModalView allows any number of modals to stack over each other and over a built-in Modal.react-native-modalfy or portal libraries.| | Native or JS | Multiple at once | Accessibility |
| --- | --- | --- | --- |
| **react-native-multiple-modals** | Native | ✅ | ✅ |
| [`Modal`](https://reactnative.dev/docs/modal) (React Native) | Native | ❌ on iOS | ✅ |
| [react-native-modal](https://github.com/react-native-modal/react-native-modal) | Native | ❌ | ✅ |
| [react-native-modalfy](https://github.com/colorfy-software/react-native-modalfy) | JS | ✅ | ❌ |
| [@react-navigation/native-stack](https://reactnavigation.org/docs/native-stack-navigator/) | Native | ✅ | ❌ |
| [@gorhom/portal](https://github.com/gorhom/react-native-portal), [react-native-portalize](https://github.com/jeremybarbet/react-native-portalize) | JS | ✅ | ❌ |ModalView is designed to always be rendered above a standard React Native Modal. This allows you to layer ModalView instances on top of existing legacy modal implementations.Use react-native-multiple-modals when you need a native implementation that supports showing multiple modals at once and provides full accessibility (WCAG) support.
Unlike the standard React Native Modal, this library allows multiple instances on iOS. Unlike JS-based solutions like react-native-modalfy or @gorhom/portal, it uses native layering, which is better for performance and integration with native components like bottom tabs.
To run E2E tests for the web platform, ensure you have Maestro CLI 2.10.0+ installed.
npx expo start --webnpm run e2e:run -- --platform web --run-steps generation testsnpm run e2e:run -- --platform web --run-steps generation testsThe ModalView component is displayed when it is mounted in the React tree and hidden when it is removed. To handle user interactions like tapping the backdrop or pressing the hardware back button, provide an onRequestDismiss callback to update your local visibility state.
import { ModalView } from "react-native-multiple-modals";
const YourComponent = () => {
const [isVisible, setVisibility] = useState(false);
return (
<View>
<Button text="Open modal" onPress={() => setVisibility(true)} />
{isVisible && (
<ModalView
animationType="fade"
onRequestDismiss={() => setVisibility(false)}
>
<YourContentView />
</ModalView>
)}
</View>
);
};On iOS, the status bar is shared across all windows. This means the internal StatusBar managed by ModalView may conflict with expo-status-bar if you are using it in your app.
To prevent this conflict and allow your own status bar component to control the appearance, pass the disableDefaultStatusBarIOS prop to ModalView.
To replace the default translucent backdrop of a ModalView with a blur effect, use the renderBackdrop prop.
Pass a function to renderBackdrop that returns a component (such as BlurView from expo-blur). The returned element is rendered inside a pressable that handles backdrop taps, so it should use style={{ flex: 1 }} to fill the available space.
Note that tapping the blurred area will trigger onRequestDismiss by default because the pressable wraps the returned element.
import { BlurView } from 'expo-blur';
import { ModalView } from 'react-native-multiple-modals';
const BlurredModal = ({ onClose, children }) => (
<ModalView
contentContainerStyle={{ justifyContent: 'center', alignItems: 'center' }}
onRequestDismiss={onClose}
renderBackdrop={() => <BlurView intensity={40} style={{ flex: 1 }} />}
>
{children}
</ModalView>
);Install the package using npm or yarn, and ensure you run pod install for iOS projects to set up the native layering capabilities.
npm i react-native-multiple-modals
# or
yarn add react-native-multiple-modals
# For iOS
pod install --project-directory=iosThe example is an Expo app that demonstrates react-native-multiple-modals on iOS, Android, and web.
Important: Because the library uses custom native (Fabric) code, you cannot use Expo Go. You must run the app as a dev build using npx expo run:ios or npx expo run:android after performing a prebuild.
cd example
npm install # links the library via file:.. and installs deps
npx expo prebuild --clean # generates ios/ + android/ (regenerable; gitignored)
npx expo run:ios # iOS simulator
npx expo run:android # Android emulator/device
npx expo start --web # web (react-native-web)