Skip to main content
Glama
stack.md12.3 kB
--- title: Stack description: Learn how to use the Stack navigator in Expo Router. hasVideoLink: true --- A stack navigator is the foundational way of navigating between routes in an app. On Android, a stacked route animates on top of the current screen. On iOS, a stacked route animates from the right. Expo Router provides a `Stack` navigation component that creates a navigation stack and allows you to add new routes in your app. This guide provides information on how you can create a `Stack` navigator in your project and customize an individual route's options and header. ## Get started You can use file-based routing to create a stack navigator. Here's an example file structure: This file structure produces a layout where the `index` route is the first route in the stack, and the `details` route is pushed on top of the `index` route when navigated. You can use the **app/\_layout.tsx** file to define your app's `Stack` navigator with these two routes: ```tsx app/_layout.tsx return ; } ``` ## Screen options and header configuration ### Statically configure route options You can use the `` component in the layout component route to statically configure a route's options. This is also useful for [tabs](/router/advanced/tabs/) or [drawers](/router/advanced/drawer/) as they need an icon defined ahead of time. ```tsx app/_layout.tsx|collapseHeight=440 return ( Click for more information on available <CODE>screenOptions</CODE> from React Navigation documentation</A>.*/ screenOptions={{ headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', headerTitleStyle: { fontWeight: 'bold', }, }}> /* @end */ {/* Optionally configure static options outside the route.*/} ); } ``` As an alternative to the `` component, you can use [`navigation.setOptions()`](https://reactnavigation.org/docs/navigation-object/#setoptions) to configure a route's options from within the route's component file. ```tsx app/index.tsx const navigation = useNavigation(); useEffect(() => { navigation.setOptions({ headerShown: false }); }, [navigation]); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> </View> ); } ``` ### Configure header bar You can configure the header bar for all routes in a `Stack` navigator by using the `screenOptions` prop. This is useful for setting a common header style across all routes. ```tsx app/_layout.tsx return ( ); } ``` To configure the header bar dynamically for an individual route, use that navigator's `<Stack.Screen>` component in the routes's file. This is useful for interactions that change the UI. ```tsx app/index.tsx function LogoTitle() { return ( ); } return ( <View style={styles.container}> <Stack.Screen options={{ /* @info <A href="https://reactnavigation.org/docs/headers/#adjusting-header-stylesheader-styles">Click for more information on adjusting header styles from React Navigation documentation</A>.*/ title: 'My home', headerStyle: { backgroundColor: '#f4511e' }, headerTintColor: '#fff', headerTitleStyle: { fontWeight: 'bold', }, /* @end */ /* @info <A href="https://reactnavigation.org/docs/headers/#replacing-the-title-with-a-custom-component">Click for more information on replacing a title with a custom component from React Navigation documentation</A>.*/ headerTitle: props => , /* @end */ }} /> <Text>Home Screen</Text> <Link href={{ pathname: 'details', params: { name: 'Bacon' } }}>Go to Details</Link> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, image: { width: 50, height: 50, }, }); ``` ### Available header options The `Stack` navigator supports comprehensive header configuration options. Below are all the header-related options available: ### Set screen options dynamically To configure a route's option dynamically, you can always use the `<Stack.Screen>` component in that route's file. As an alternative, you can also use the [imperative API's `router.setParams()`](/versions/latest/sdk/router/#router) function to configure the route dynamically. ```tsx app/details.tsx const router = useRouter(); const params = useLocalSearchParams(); return ( <View style={styles.container}> <Text onPress={() => { router.setParams({ name: 'Updated' }); }}> Update the title </Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, }); ``` ### Header buttons You can add buttons to the header by using the `headerLeft` and `headerRight` options. These options accept a React component that renders in the header. ```tsx app/index.tsx function LogoTitle() { return ( ); } const [count, setCount] = useState(0); return ( <> <Stack.Screen options={{ headerTitle: props => , headerRight: () => <Button onPress={() => setCount(c => c + 1)} title="Update count" />, }} /> <Text>Count: {count}</Text> </> ); } const styles = StyleSheet.create({ image: { width: 50, height: 50, }, }); ``` ### Other screen options For a complete list of all available other screen options including animations, gestures, and other configurations: ## Custom push behavior By default, the `Stack` navigator removes duplicate screens when pushing a route that is already in the stack. For example, if you push the same screen twice, the second push will be ignored. You can change this push behavior by providing a custom `getId()` function to the `<Stack.Screen>`. For example, the `index` route in the following layout structure shows a list of different user profiles in the app. Let's make the `[details]` route a [dynamic route](/router/basics/notation/#square-brackets) so that the app user can navigate to see a profile's details. The `Stack` navigator will push a new screen every time the app user navigates to a different profile but will fail. If you provide a `getId()` function that returns a new ID every time, the `Stack` will push a new screen every time the app user navigates to a profile. You can use the `<Stack.Screen name="[profile]" getId={}>` component in the layout component route to modify the push behavior: ```tsx app/_layout.tsx return ( <Stack> <Stack.Screen name="[profile]" getId={ /* @info Returning a new ID every time will cause every page to push. */ ({ params }) => String(Date.now()) /* @end */ } /> ); } ``` ## Removing stack screens There are different actions you can use to dismiss and remove one or many routes from a stack. ### `dismiss` action Dismisses the last screen in the closest stack. If the current screen is the only route in the stack, it will dismiss the entire stack. You can optionally pass a positive number to dismiss up to that specified number of screens. Dismiss is different from `back` as it targets the closest stack and not the current navigator. If you have nested navigators, calling `dismiss` will take you back multiple screens. {/* prettier-ignore */} ```tsx app/settings.tsx /* @info Import useRouter from Expo Router. */ /* @end */ /* @info Access the router from the useRouter hook. */ const router = useRouter(); /* @end */ const handleDismiss = (count: number) => { /* @info In the handler method, call router.dismiss to go back. */ router.dismiss(count) /* @end */ }; return ( /* @info Trigger the handler method on a touchable or button component. */ <Button title="Go to first screen" onPress={() => handleDismiss(3)} /> /* @end */ ); } ``` ### `dismissTo` action > `dismissTo` was added in Expo Router `4.0.8`. It operates similarly to the `navigation` function in Expo Router v3. Dismisses screens in the current `` until the specified `Href` is reached. If the `Href` is absent in the history, a `push` action will be performed instead. For example, consider the history of `/one`, `/two`, `/three` routes, where `/three` is the current route. The action `router.dismissTo('/one')` will cause the history to go back twice, while `router.dismissTo('/four')` will `push` the history forward to the `/four` route. {/* prettier-ignore */} ```tsx app/settings.tsx /* @info Import useRouter from Expo Router. */ /* @end */ /* @info Access the router from the useRouter hook. */ const router = useRouter(); /* @end */ const handleDismissAll = () => { /* @info In the handler method, call router.dismissTo to go back to a specific route. */ router.dismissTo('/') /* @end */ }; return ( /* @info Trigger the handler method on a touchable or button component. */ /* @end */ ); } ``` ### `dismissAll` action To return to the first screen in the closest stack. This is similar to [`popToTop`](https://reactnavigation.org/docs/stack-actions/#poptotop) stack action. For example, the `home` route is the first screen, and the `settings` is the last. To go from `settings` to `home` route you'll have to go back to `details`. However, using the `dismissAll` action, you can go from `settings` to `home` and dismiss any screen in between. {/* prettier-ignore */} ```tsx app/settings.tsx /* @info Import useRouter from Expo Router. */ /* @end */ /* @info Access the router from the useRouter hook. */ const router = useRouter(); /* @end */ const handleDismissAll = () => { /* @info In the handler method, call router.dismissAll to go back to the first screen in a stack. */ router.dismissAll() /* @end */ }; return ( /* @info Trigger the handler method on a touchable or button component. */ /* @end */ ); } ``` ### `canDismiss` action To check if it is possible to dismiss the current screen. Returns `true` if the router is within a stack with more than one screen in the stack's history. {/* prettier-ignore */} ```tsx app/settings.tsx|collapseHeight=410 /* @info Import useRouter from Expo Router. */ /* @end */ /* @info Access the router from useRouter hook. */ const router = useRouter(); /* @end */ const handleDismiss = (count: number) => { /* @info Check if we can dismiss. */ if (router.canDismiss()) { /* @info In the handler method, call router.dismiss to go back to. */ router.dismiss(count) /* @end */ } /* @end */ }; return ( /* @info Trigger the handler method on a touchable or button component. */ <Button title="Maybe dismiss" onPress={() => handleDismiss()} /> /* @end */ ); } ``` ## Relation with Native Stack Navigator The `Stack` navigator in Expo Router wraps the [Native Stack Navigator](https://reactnavigation.org/docs/native-stack-navigator) from React Navigation. Options available in the Native Stack Navigator are all available in the `Stack` navigator in Expo Router. ### JavaScript stack with @react-navigation/stack You can also use the JavaScript-powered `@react-navigation/stack` library to create a custom layout component by wrapping this library with the `withLayoutContext`. In the following example, `JsStack` component is defined using `@react-navigation/stack` library: ```tsx layouts/js-stack.tsx import { createStackNavigator, StackNavigationEventMap, StackNavigationOptions, } from '@react-navigation/stack'; const { Navigator } = createStackNavigator(); StackNavigationOptions, typeof Navigator, StackNavigationState<ParamListBase>, StackNavigationEventMap >(Navigator); ``` After defining the `JsStack` component, you can use it in your app: {/* prettier-ignore */} ```tsx app/_layout.tsx return ( ); } ``` For more information on available options, see [`@react-navigation/stack` documentation](https://reactnavigation.org/docs/stack-navigator).

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server