Opening a full-screen modal
A modal displays content that temporarily blocks interactions with the main view.
A modal is like a popup — it's not part of your primary navigation flow — it usually has a different transition, a different way to dismiss it, and is intended to focus on one particular piece of content or interaction.
The purpose of explaining this as part of the React Navigation fundamentals is not only because this is a common use case, but also because the implementation requires knowledge of nesting navigators, which is an important part of React Navigation.
Creating a modal stack
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is the home screen!</Text>
<Button
onPress={() => navigation.navigate('MyModal')}
title="Open Modal"
/>
</View>
);
}
function DetailsScreen() {
return (
<View>
<Text>Details</Text>
</View>
);
}
function ModalScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is a modal!</Text>
<Button onPress={() => navigation.goBack()} title="Dismiss" />
</View>
);
}
const MainStack = createStackNavigator();
const RootStack = createStackNavigator();
function MainStackScreen() {
return (
<MainStack.Navigator>
<MainStack.Screen name="Home" component={HomeScreen} />
<MainStack.Screen name="Details" component={DetailsScreen} />
</MainStack.Navigator>
);
}
function RootStackScreen() {
return (
<RootStack.Navigator mode="modal">
<RootStack.Screen
name="Main"
component={MainStackScreen}
options={{ headerShown: false }}
/>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Navigator>
);
}
There are some important things to notice here:
-
We are using our
MainStackScreen
component as a screen insideRootStackScreen
! By doing this, we are nesting a stack navigator inside of another stack navigator. In this case, this is useful for us because we want to use a different transition style for the modal. SinceRootStackScreen
renders a stack navigator and has its own header, we also want to hide the header for this screen. In the future this will be important because for tab navigation, for example, each tab will likely have its own stack! Intuitively, this is what you expect: when you are on tab A and switch to tab B, you would like tab A to maintain its navigation state as you continue to explore tab B. Look at this diagram to visualize the structure of navigation in this example: -
The
mode
prop for stack navigator can be eithercard
(default) ormodal
. Themodal
behavior slides the screen in from the bottom on iOS and allows the user to swipe down from the top to dismiss it. Themodal
prop has no effect on Android because full-screen modals don't have any different transition behavior on the platform. -
When we call
navigate
we don't have to specify anything except the route that we'd like to navigate to. There is no need to qualify which stack it belongs to (the arbitrarily named 'root' or the 'main' stack) — React Navigation attempts to find the route on the closest navigator and then performs the action there. To visualize this, look again at the above tree diagram and imagine thenavigate
action flowing up fromHomeScreen
toMainStack
. We know thatMainStack
can't handle the routeMyModal
, so it then flows it up toRootStack
, which can handle that route, and so it does.
Summary
- To change the type of transition on a stack navigator you can use the
mode
prop. When set tomodal
, all screens animate-in from bottom to top rather than right to left. This applies to that entire stack navigator, so to use right to left transitions on other screens, we add another navigation stack with the default configuration. navigation.navigate
traverses up the navigator tree to find a navigator that can handle thenavigate
action.