---
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).