xref: /expo/docs/pages/router/advanced/stack.mdx (revision 703fa4b5)
1---
2title: Stack
3description: Learn how to use the Stack Layout in Expo Router.
4---
5
6import { FileTree } from '~/ui/components/FileTree';
7import { BoxLink } from '~/ui/components/BoxLink';
8import { BookOpen02Icon } from '@expo/styleguide-icons';
9
10The `Stack` Layout in Expo Router wraps the [Native Stack Navigator](https://reactnavigation.org/docs/native-stack-navigator) from React Navigation, not to be confused with the legacy [JS Stack Navigator](https://reactnavigation.org/docs/stack-navigator).
11
12<FileTree files={['app/_layout.js', 'app/index.js', 'app/detail.js']} />
13
14To create a `Stack` layout with two screens as shown in the file structure above:
15
16```js app/_layout.js
17import { Stack } from 'expo-router/stack';
18
19export default function Layout() {
20  return <Stack />;
21}
22```
23
24## Configure header bar
25
26Use the `screenOptions` prop to configure the header bar.
27
28```js app/_layout.js
29import { Stack } from 'expo-router';
30
31export default function Layout() {
32  return (
33    <Stack
34      screenOptions={{
35        headerStyle: {
36          backgroundColor: '#f4511e',
37        },
38        headerTintColor: '#fff',
39        headerTitleStyle: {
40          fontWeight: 'bold',
41        },
42      }}
43    />
44  );
45}
46```
47
48You can use a layout's Screen component to configure the header bar dynamically from within the route. This is good for interactions that change the UI.
49
50```js app/home.js
51import { Link, Stack } from 'expo-router';
52import { Image, Text, View } from 'react-native';
53
54function LogoTitle() {
55  return (
56    <Image
57      style={{ width: 50, height: 50 }}
58      source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
59    />
60  );
61}
62
63export default function Home() {
64  return (
65    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
66      <Stack.Screen
67        options={{
68          // https://reactnavigation.org/docs/headers#setting-the-header-title
69          title: 'My home',
70          // https://reactnavigation.org/docs/headers#adjusting-header-styles
71          headerStyle: { backgroundColor: '#f4511e' },
72          headerTintColor: '#fff',
73          headerTitleStyle: {
74            fontWeight: 'bold',
75          },
76          // https://reactnavigation.org/docs/headers#replacing-the-title-with-a-custom-component
77          headerTitle: props => <LogoTitle {...props} />,
78        }}
79      />
80      <Text>Home Screen</Text>
81      <Link href={{ pathname: 'details', params: { name: 'Bacon' } }}>Go to Details</Link>
82    </View>
83  );
84}
85```
86
87You can use the imperative API `router.setParams()` function to configure the route dynamically.
88
89```js app/details.js
90import { View, Text } from 'react-native';
91import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
92
93export default function Details() {
94  const router = useRouter();
95  const params = useLocalSearchParams();
96
97  return (
98    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
99      <Stack.Screen
100        options={{
101          title: params.name,
102        }}
103      />
104      <Text
105        onPress={() => {
106          router.setParams({ name: 'Updated' });
107        }}>
108        Update the title
109      </Text>
110    </View>
111  );
112}
113```
114
115## Header buttons
116
117With the following file structure:
118
119<FileTree files={['app/_layout.js', 'app/home.js']} />
120
121You can use the `<Stack.Screen name={routeName} />` component in the layout component route to statically configure screen options. This is useful for tab bars or drawers which need to have an icon defined ahead of time.
122
123```js app/_layout.js
124import { Stack } from 'expo-router';
125
126export default function Layout() {
127  return (
128    <Stack
129      // https://reactnavigation.org/docs/headers#sharing-common-options-across-screens
130      /* @info */
131      screenOptions={{
132        headerStyle: {
133          backgroundColor: '#f4511e',
134        },
135        headerTintColor: '#fff',
136        headerTitleStyle: {
137          fontWeight: 'bold',
138        },
139      }}>
140      /* @end */
141      {/* Optionally configure static options outside the route. */}
142      /* @info */
143      <Stack.Screen name="home" options={{}} />
144      /* @end */
145    </Stack>
146  );
147}
148```
149
150Use the `<Stack.Screen />` component in the child route to dynamically configure options.
151
152```js app/home.js
153import { useLayoutEffect } from 'react';
154import { View, Button, Text, Image } from 'react-native';
155/* @info */
156import { Stack } from 'expo-router';
157/* @end */
158
159function LogoTitle() {
160  return (
161    <Image
162      style={{ width: 50, height: 50 }}
163      source={require('@expo/snack-static/react-native-logo.png')}
164    />
165  );
166}
167
168export default function Home() {
169  const [count, setCount] = React.useState(0);
170
171  return (
172    <>
173      /* @info */
174      <Stack.Screen
175        options={{
176          headerTitle: props => <LogoTitle {...props} />,
177          headerRight: () => <Button onPress={() => setCount(c => c + 1)} title="Update count" />,
178        }}
179      />
180      /* @end */
181      <Text>Count: {count}</Text>
182    </>
183  );
184}
185```
186
187## Next steps
188
189<BoxLink
190  title="Native Stack Navigator: Options"
191  Icon={BookOpen02Icon}
192  description="For a list of all options, see React Navigation's documentation."
193  href="https://reactnavigation.org/docs/native-stack-navigator#options"
194/>
195
196<BoxLink
197  title="Tabs layout"
198  Icon={BookOpen02Icon}
199  description="Learn how to use Tabs layout in Expo Router."
200  href="/router/advanced/tabs"
201/>
202