xref: /expo/docs/pages/router/advanced/stack.mdx (revision df35d4e9)
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```jsx 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```jsx 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```jsx 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```jsx 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```jsx app/home.js
153import { Button, Text, Image } from 'react-native';
154/* @info */
155import { Stack } from 'expo-router';
156/* @end */
157
158function LogoTitle() {
159  return (
160    <Image
161      style={{ width: 50, height: 50 }}
162      source={require('@expo/snack-static/react-native-logo.png')}
163    />
164  );
165}
166
167export default function Home() {
168  const [count, setCount] = React.useState(0);
169
170  return (
171    <>
172      /* @info */
173      <Stack.Screen
174        options={{
175          headerTitle: props => <LogoTitle {...props} />,
176          headerRight: () => <Button onPress={() => setCount(c => c + 1)} title="Update count" />,
177        }}
178      />
179      /* @end */
180      <Text>Count: {count}</Text>
181    </>
182  );
183}
184```
185
186## Next steps
187
188<BoxLink
189  title="Native Stack Navigator: Options"
190  Icon={BookOpen02Icon}
191  description="For a list of all options, see React Navigation's documentation."
192  href="https://reactnavigation.org/docs/native-stack-navigator#options"
193/>
194
195<BoxLink
196  title="Tabs layout"
197  Icon={BookOpen02Icon}
198  description="Learn how to use Tabs layout in Expo Router."
199  href="/router/advanced/tabs"
200/>
201