Stack Navigator
Stack Navigator provides a way for your app to transition between screens where each new screen is placed on top of a stack.
By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, use OS default animation on Android. But the animations can be customized to match your needs.
One thing to keep in mind is that while @react-navigation/stack is extremely customizable, it's implemented in JavaScript. While it runs animations and gestures using natively, the performance may not be as fast as a native implementation. This may not be an issue for a lot of apps, but if you're experiencing performance issues during navigation, consider using @react-navigation/native-stack instead - which uses native navigation primitives.
Installation
To use this navigator, ensure that you have @react-navigation/native and its dependencies (follow this guide), then install @react-navigation/stack:
- npm
- Yarn
- pnpm
npm install @react-navigation/stack
yarn add @react-navigation/stack
pnpm add @react-navigation/stack
Then, you need to install and configure the libraries that are required by the stack navigator:
-
First, install
react-native-gesture-handler.If you have a Expo managed project, in your project directory, run:
npx expo install react-native-gesture-handlerIf you have a bare React Native project, in your project directory, run:
- npm
- Yarn
- pnpm
npm install react-native-gesture-handleryarn add react-native-gesture-handlerpnpm add react-native-gesture-handler -
To finalize installation of
react-native-gesture-handler, add the following at the top (make sure it's at the top and there's nothing else before it) of your entry file, such asindex.jsorApp.js:import 'react-native-gesture-handler';warningIf you are building for Android or iOS, do not skip this step, or your app may crash in production even if it works fine in development. This is not applicable to other platforms.
-
Optionally, you can also install
@react-native-masked-view/masked-view. This is needed if you want to use UIKit style animations for the header (HeaderStyleInterpolators.forUIKit).If you have a Expo managed project, in your project directory, run:
npx expo install @react-native-masked-view/masked-viewIf you have a bare React Native project, in your project directory, run:
- npm
- Yarn
- pnpm
npm install @react-native-masked-view/masked-viewyarn add @react-native-masked-view/masked-viewpnpm add @react-native-masked-view/masked-view -
If you're on a Mac and developing for iOS, you also need to install the pods (via Cocoapods) to complete the linking.
npx pod-install ios
API Definition
To use this navigator, import it from @react-navigation/stack:
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Notifications" component={Notifications} />
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
);
}
Props
The Stack.Navigator component accepts following props:
id
Optional unique ID for the navigator. This can be used with navigation.getParent to refer to this navigator in a child navigator.
initialRouteName
The name of the route to render on first load of the navigator.
screenOptions
Default options to use for the screens in the navigator.
detachInactiveScreens
Boolean used to indicate whether inactive screens should be detached from the view hierarchy to save memory. This enables integration with react-native-screens. Defaults to true.
If you need to disable this optimization for specific screens (e.g. you want to screen to stay in view even when unfocused) detachPreviousScreen option.
keyboardHandlingEnabled
If false, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen. Defaults to true.
Options
The following options can be used to configure the screens in the navigator. These can be specified under screenOptions prop of Stack.navigator or options prop of Stack.Screen.
title
String that can be used as a fallback for headerTitle.
cardShadowEnabled
Use this prop to have visible shadows during transitions. Defaults to true.
cardOverlayEnabled
Use this prop to have a semi-transparent dark overlay visible under the card during transitions. Defaults to true on Android and false on iOS.
cardOverlay
Function which returns a React Element to display as the overlay for the card. Make sure to set cardOverlayEnabled to true when using this.
cardStyle
Style object for the card in stack. You can provide a custom background color to use instead of the default background here.
You can also specify { backgroundColor: 'transparent' } to make the previous screen visible underneath (for transparent modals). This is useful to implement things like modal dialogs. You should also specify presentation: 'modal' in the options when using a transparent background so previous screens aren't detached and stay visible underneath.
On Web, the height of the screen isn't limited to the height of the viewport. This is by design to allow the browser's address bar to hide when scrolling. If this isn't desirable behavior, you can set cardStyle to { flex: 1 } to force the screen to fill the viewport.
presentation
This is shortcut option which configures several options to configure the style for rendering and transitions:
card: Use the default OS animations for iOS and Android screen transitions.modal: Use Modal animations. This changes a few things:- Sets
headerModetoscreenfor the screen unless specified otherwise. - Changes the screen animation to match the platform behavior for modals.
- Sets
transparentModal: Similar tomodal. This changes following things:- Sets
headerModetoscreenfor the screen unless specified otherwise. - Sets background color of the screen to transparent, so previous screen is visible
- Adjusts the
detachPreviousScreenoption so that the previous screen stays rendered. - Prevents the previous screen from animating from its last position.
- Changes the screen animation to a vertical slide animation.
- Sets
See Transparent modals for more details on how to customize transparentModal.
animationEnabled
Whether transition animation should be enabled on the screen. If you set it to false, the screen won't animate when pushing or popping. Defaults to true on iOS and Android, false on Web.
animationTypeForReplace
The type of animation to use when this screen replaces another screen. It takes the following values:
push- The animation of a new screen being pushed will be usedpop- The animation of a screen being popped will be used
Defaults to push.
When pop is used, the pop animation is applied to the screen being replaced.
gestureEnabled
Whether you can use gestures to dismiss this screen. Defaults to true on iOS, false on Android.
Gestures are not supported on Web.
gestureResponseDistance
Number to override the distance of touch start from the edge of the screen to recognize gestures.
It'll configure either the horizontal or vertical distance based on the gestureDirection value.
The default values are:
50- whengestureDirectionishorizontalorhorizontal-inverted135- whengestureDirectionisverticalorvertical-inverted
This is not supported on Web.
gestureVelocityImpact
Number which determines the relevance of velocity for the gesture. Defaults to 0.3.
This is not supported on Web.
gestureDirection
Direction of the gestures. Refer the Animations section for details.
This is not supported on Web.
transitionSpec
Configuration object for the screen transition. Refer the Animations section for details.
cardStyleInterpolator
Interpolated styles for various parts of the card. Refer the Animations section for details.
headerStyleInterpolator
Interpolated styles for various parts of the header. Refer the Animations section for details.
detachPreviousScreen
Boolean used to indicate whether to detach the previous screen from the view hierarchy to save memory. Set it to false if you need the previous screen to be seen through the active screen. Only applicable if detachInactiveScreens isn't set to false.
This is automatically adjusted when using presentation as transparentModal or modal to keep the required screens visible. Defaults to true in other cases.
freezeOnBlur
Boolean indicating whether to prevent inactive screens from re-rendering. Defaults to false.
Defaults to true when enableFreeze() from react-native-screens package is run at the top of the application.
Requires react-native-screens version >=3.16.0.
Only supported on iOS and Android.
Header related options
You can find the list of header related options here. These options can be specified under screenOptions prop of Stack.navigator or options prop of Stack.Screen. You don't have to be using @react-navigation/elements directly to use these options, they are just documented in that page.
In addition to those, the following options are also supported in stack:
header
Custom header to use instead of the default header.
This accepts a function that returns a React Element to display as a header. The function receives an object containing the following properties as the argument:
navigation- The navigation object for the current screen.route- The route object for the current screen.options- The options for the current screenlayout- Dimensions of the screen, containsheightandwidthproperties.progressAnimated nodes representing the progress of the animation.back- Options for the back button, contains an object with atitleproperty to use for back button label.styleInterpolator- Function which returns interpolated styles for various elements in the header.
Make sure to set headerMode to screen as well when using a custom header (see below for more details).
Example:
import { getHeaderTitle } from '@react-navigation/elements';
// ..
header: ({ navigation, route, options, back }) => {
const title = getHeaderTitle(options, route.name);
return (
<MyHeader
title={title}
leftButton={
back ? <MyBackButton onPress={navigation.goBack} /> : undefined
}
style={options.headerStyle}
/>
);
};
To set a custom header for all the screens in the navigator, you can specify this option in the screenOptions prop of the navigator.
When using a custom header, there are 2 things to keep in mind:
Specify a height in headerStyle to avoid glitches
If your header's height differs from the default header height, then you might notice glitches due to measurement being async. Explicitly specifying the height will avoid such glitches.
Example:
headerStyle: {
height: 80, // Specify the height of your custom header
};
Note that this style is not applied to the header by default since you control the styling of your custom header. If you also want to apply this style to your header, use headerStyle from the props.
Set headerMode to float for custom header animations
By default, there is one floating header which renders headers for multiple screens on iOS for non-modals. These headers include animations to smoothly switch to one another.
If you specify a custom header, React Navigation will change it to screen automatically so that the header animated along with the screen instead. This means that you don't have to implement animations to animate it separately.
But you might want to keep the floating header to have a different transition animation between headers. To do that, you'll need to specify headerMode: 'float' in the options, and then interpolate on the progress.current and progress.next props in your custom header. For example, following will cross-fade the header:
const opacity = Animated.add(progress.current, progress.next || 0).interpolate({
inputRange: [0, 1, 2],
outputRange: [0, 1, 0],
});
return (
<Animated.View style={{ opacity }}>{/* Header content */}</Animated.View>
);
headerMode
Specifies how the header should be rendered:
float- Render a single header that stays at the top and animates as screens are changed. This is default on iOS.screen- Each screen has a header attached to it and the header fades in and out together with the screen. This is default on other platforms.
headerShown
Whether to show or hide the header for the screen. The header is shown by default. Setting this to false hides the header.
headerBackAllowFontScaling
Whether back button title font should scale to respect Text Size accessibility settings. Defaults to false.
headerBackAccessibilityLabel
Accessibility label for the header back button.
headerBackImage
Function which returns a React Element to display custom image in header's back button. When a function is used, it receives the tintColor in it's argument object. Defaults to Image component with back image source, which is the default back icon image for the platform (a chevron on iOS and an arrow on Android).
headerBackTitle
Title string used by the back button on iOS. Defaults to the previous scene's headerTitle.
headerBackTitleVisible
A reasonable default is supplied for whether the back button title should be visible or not, but if you want to override that you can use true or false in this option.
headerTruncatedBackTitle
Title string used by the back button when headerBackTitle doesn't fit on the screen. "Back" by default.
headerBackTitleStyle
Style object for the back title.
Events
The navigator can emit events on certain actions. Supported events are:
transitionStart
This event is fired when the transition animation starts for the current screen.
Event data:
e.data.closing- Boolean indicating whether the screen is being opened or closed.
Example:
React.useEffect(() => {
const unsubscribe = navigation.addListener('transitionStart', (e) => {
// Do something
});
return unsubscribe;
}, [navigation]);
transitionEnd
This event is fired when the transition animation ends for the current screen.
Event data:
e.data.closing- Boolean indicating whether the screen was opened or closed.
Example:
React.useEffect(() => {
const unsubscribe = navigation.addListener('transitionEnd', (e) => {
// Do something
});
return unsubscribe;
}, [navigation]);
gestureStart
This event is fired when the swipe gesture starts for the current screen.
Example:
React.useEffect(() => {
const unsubscribe = navigation.addListener('gestureStart', (e) => {
// Do something
});
return unsubscribe;
}, [navigation]);
gestureEnd
This event is fired when the swipe gesture ends for the current screen. e.g. a screen was successfully dismissed.
Example:
React.useEffect(() => {
const unsubscribe = navigation.addListener('gestureEnd', (e) => {
// Do something
});
return unsubscribe;
}, [navigation]);
gestureCancel
This event is fired when the swipe gesture is cancelled for the current screen. e.g. a screen wasn't dismissed by the gesture.
Example:
React.useEffect(() => {
const unsubscribe = navigation.addListener('gestureCancel', (e) => {
// Do something
});
return unsubscribe;
}, [navigation]);
Helpers
The stack navigator adds the following methods to the navigation prop: