Reference version

This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

NavigationStack

A SwiftUI NavigationStack, with the links and destinations that push views onto it.

iOS
tvOS
Included in Expo Go
Recommended version:
~58.0.14

Expo UI NavigationStack matches the official SwiftUI NavigationStack API and shows a root view that can push other views on top of it.

Tapping a NavigationLink pushes the NavigationDestination with the same value.

Installation

Terminal
- npx expo install @expo/ui
- yarn expo install @expo/ui
- pnpm expo install @expo/ui
- bun expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

Usage

Basic navigation

Put the root view and the destinations inside the stack. Give a link and its destination the same value. Set the title of each screen with the navigationTitle modifier.

NavigationStackExample.tsx
import { Host, List, NavigationDestination, NavigationLink, NavigationStack, Text, VStack, } from '@expo/ui/swift-ui'; import { navigationTitle, padding, } from '@expo/ui/swift-ui/modifiers'; export default function NavigationStackExample() { return ( <Host style={{ flex: 1 }}> <NavigationStack> <List modifiers={[navigationTitle('Settings')]}> <NavigationLink value="account"> <Text>Account</Text> </NavigationLink> <NavigationLink value="notifications"> <Text>Notifications</Text> </NavigationLink> </List> <NavigationDestination value="account"> <VStack modifiers={[ padding({ all: 20 }), navigationTitle('Account'), ]}> <Text>Signed in as bird@example.com</Text> </VStack> </NavigationDestination> <NavigationDestination value="notifications"> <VStack modifiers={[ padding({ all: 20 }), navigationTitle('Notifications'), ]}> <Text>All notifications are on.</Text> </VStack> </NavigationDestination> </NavigationStack> </Host> ); }

Inside a List, a link renders as a row with a chevron. A destination has to be a direct child of the stack, however deeply the link that pushes it is nested.

A link can wrap any view.

NavigationLinkCardExample.tsx
import { Host, HStack, Image, NavigationDestination, NavigationLink, NavigationStack, Spacer, Text, VStack, } from '@expo/ui/swift-ui'; import { font, foregroundStyle, navigationTitle, padding, } from '@expo/ui/swift-ui/modifiers'; export default function NavigationLinkCardExample() { return ( <Host style={{ flex: 1 }}> <NavigationStack> <VStack modifiers={[ padding({ all: 20 }), navigationTitle('Today'), ]}> <NavigationLink value="report"> <HStack spacing={12}> <Image systemName="chart.bar.fill" size={28} /> <VStack alignment="leading" spacing={2}> <Text modifiers={[font({ textStyle: 'headline' })]}> Weekly report </Text> <Text modifiers={[ font({ textStyle: 'caption' }), foregroundStyle('secondaryLabel'), ]}> Ready to read </Text> </VStack> <Spacer /> </HStack> </NavigationLink> </VStack> <NavigationDestination value="report"> <VStack modifiers={[ padding({ all: 20 }), navigationTitle('Weekly report'), ]}> <Text>Sessions are up by 12% on last week.</Text> </VStack> </NavigationDestination> </NavigationStack> </Host> ); }

Read and set the path

The stack keeps its own path by default. Pass path and onPathChange to drive it from state. The path holds the value of each pushed view, in push order. Set it to an empty array to return to the root view.

NavigationStackPathExample.tsx
import { Button, Host, List, NavigationDestination, NavigationLink, NavigationStack, Text, VStack, } from '@expo/ui/swift-ui'; import { navigationTitle, padding, } from '@expo/ui/swift-ui/modifiers'; import { useState } from 'react'; const ARTICLES = ['Nesting', 'Migration', 'Song']; export default function NavigationStackPathExample() { const [path, setPath] = useState<string[]>([]); return ( <Host style={{ flex: 1 }}> <NavigationStack path={path} onPathChange={setPath}> <List modifiers={[navigationTitle('Articles')]}> {ARTICLES.map(article => ( <NavigationLink key={article} value={article}> <Text>{article}</Text> </NavigationLink> ))} </List> {ARTICLES.map(article => ( <NavigationDestination key={article} value={article}> <VStack spacing={12} modifiers={[ padding({ all: 20 }), navigationTitle(article), ]}> <Text> The chapter about {article.toLowerCase()}. </Text> <Button label="Back to the articles" onPress={() => setPath([])} /> </VStack> </NavigationDestination> ))} </NavigationStack> </Host> ); }

Add buttons to the navigation bar

Wrap the content in a Toolbar and put the buttons in Toolbar.Content.

API

import { NavigationDestination, NavigationLink, NavigationStack, } from '@expo/ui/swift-ui';

Component

iOS

Type: React.Element<NavigationStackProps>

A view that displays a root view and enables you to present additional views over the root view.

Example

const [path, setPath] = useState<string[]>([]); <NavigationStack path={path} onPathChange={setPath}> <List> <NavigationLink value="settings"> <Text>Settings</Text> </NavigationLink> </List> <NavigationDestination value="settings"> <SettingsScreen /> </NavigationDestination> </NavigationStack>

NavigationStackProps

children

iOS
Type: ReactNode

The root view of the stack, and the NavigationDestination views the stack can push. It is displayed inside a navigation bar.

onPathChange

iOS
Optional • Type: (path: string[]) => void

Callback function that is called when the stack pushes or pops a view, for example when a NavigationLink is tapped or the user swipes back. Gets called with the new path.

When path is set, the stack is controlled: a push takes effect once the new path comes back through this prop.

path

iOS
Optional • Type: string[]

The values of the views pushed on top of the root view, in the order they were pushed. Leave it undefined to let the stack manage its own path.

Component

iOS

Type: React.Element<NavigationLinkProps>

A view that controls a navigation presentation. In a List it renders as a row with a disclosure chevron, and tapping it pushes the matching NavigationDestination.

The link has to be inside the NavigationStack itself. Content presented from the stack, such as a BottomSheet or a Popover, is its own presentation context and does not reach the stack's destinations, so give that content its own NavigationStack.

Example

<NavigationLink value="settings"> <Text>Settings</Text> </NavigationLink>

NavigationLinkProps

children

iOS
Type: ReactNode

A view that describes the link.

value

iOS
Type: string

The value to append to the enclosing NavigationStack's path when the link is tapped. The stack presents the NavigationDestination whose value matches.

Component

iOS

Type: React.Element<NavigationDestinationProps>

Associates a destination view with a NavigationLink value, matching SwiftUI's navigationDestination(for:destination:). It must be a direct child of the NavigationStack, however deeply the link that pushes it is nested inside that stack.

Keep it mounted so the pushed screen already carries its navigationTitle when the slide starts, or render one for each value on the stack's path to build screens on demand.

Example

<NavigationDestination value="settings"> <SettingsScreen /> </NavigationDestination>

NavigationDestinationProps

children

iOS
Type: ReactNode

The view pushed onto the stack for value.

value

iOS
Type: string

The NavigationLink value this destination is presented for.