← Files Building React Native AppsARCHIVED FILE
skills/react-navigation/references/stacks.md
11.7 KB · Sep 30, 2026 · 23:14 UTC
---
title: Native Stack Navigator
impact: HIGH
tags: react-navigation, native-stack, navigation, header, header-items, search-bar, large-title, modal, animation, form-sheet
---
# Skill: Native Stack Navigator
## Description
Use `createNativeStackNavigator` for screen-to-screen flows.
## When to Use
- Building the default push-based flow for an app
- Using platform-native headers, large titles, or a native search bar
- Presenting modal or sheet screens with native-stack presentations
## Basic Example
**Static API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const AppStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
```
**Dynamic API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
```
## Common Features
### Large Title
Use `headerLargeTitleEnabled: true` for an iOS large title that collapses into the regular header on scroll.
**Static API**
```tsx
const AppStack = createNativeStackNavigator({
screens: {
Library: {
screen: LibraryScreen,
options: {
headerLargeTitleEnabled: true,
},
},
},
});
```
**Dynamic API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Library"
component={LibraryScreen}
options={{
headerLargeTitleEnabled: true,
}}
/>
</Stack.Navigator>
);
}
```
- Only supported on iOS.
- The scroll view in the screen must use `contentInsetAdjustmentBehavior="automatic"`.
- Don't set a background color on the header if large title is enabled as it makes title invisible on iOS 26.
- Don't set `headerTransparent: false` if large title is enabled.
- If the scrollable area does not fill the screen, the large title will not collapse on scroll.
### Header Search Bar
Use `headerSearchBarOptions` to render a native search bar. If the search configuration depends on screen state, update it with `navigation.setOptions(...)`.
**Static API**
```tsx
const AppStack = createNativeStackNavigator({
screens: {
Search: {
screen: SearchScreen,
options: {
headerSearchBarOptions: {
placeholder: 'Search',
},
},
},
},
});
```
**Dynamic API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Search"
component={SearchScreen}
options={{
headerSearchBarOptions: {
placeholder: 'Search',
},
}}
/>
</Stack.Navigator>
);
}
```
- The scroll view in the screen must use `contentInsetAdjustmentBehavior="automatic"`.
- If the screen doesn't have a scroll view, use `headerTopInsetEnabled: true`.
### Header Buttons and Custom Content
Use `unstable_headerLeftItems` and `unstable_headerRightItems` for native iOS header buttons or menus. Use `headerLeft`, `headerRight`, `headerTitle`, and `headerBackground` for custom React content, and as a fallback on other platforms.
**Static API**
```tsx
import { Button, Text, View } from 'react-native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const AppStack = createNativeStackNavigator({
screens: {
Profile: {
screen: ProfileScreen,
options: {
headerTitle: ({ tintColor, children }) => (
<Text style={{ color: tintColor, fontSize: 18 }}>{children}</Text>
),
headerBackground: () => (
<View style={{ flex: 1, backgroundColor: '#fff' }} />
),
unstable_headerLeftItems: () => [
{
type: 'button',
label: 'Edit',
onPress: () => {
// Do something
},
},
],
unstable_headerRightItems: () => [
{
type: 'button',
label: 'Done',
icon: {
type: 'sfSymbol',
name: 'checkmark',
},
onPress: () => {
// Do something
},
},
],
headerLeft: ({ tintColor }) => (
<Button title="Edit" color={tintColor} onPress={() => {}} />
),
headerRight: ({ tintColor }) => (
<Button title="Done" color={tintColor} onPress={() => {}} />
),
},
},
},
});
```
**Dynamic API**
```tsx
import { Button, Text, View } from 'react-native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{
headerTitle: ({ tintColor, children }) => (
<Text style={{ color: tintColor, fontSize: 18 }}>{children}</Text>
),
headerBackground: () => (
<View style={{ flex: 1, backgroundColor: '#fff' }} />
),
unstable_headerLeftItems: () => [
{
type: 'button',
label: 'Edit',
onPress: () => {
// Do something
},
},
],
unstable_headerRightItems: () => [
{
type: 'button',
label: 'Done',
icon: {
type: 'sfSymbol',
name: 'checkmark',
},
onPress: () => {
// Do something
},
},
],
headerLeft: ({ tintColor }) => (
<Button title="Edit" color={tintColor} onPress={() => {}} />
),
headerRight: ({ tintColor }) => (
<Button title="Done" color={tintColor} onPress={() => {}} />
),
}}
/>
</Stack.Navigator>
);
}
```
- `unstable_headerLeftItems` and `unstable_headerRightItems` are only supported on iOS and override `headerLeft` and `headerRight` when both are specified.
- Use `headerLeft` when replacing the back button. Add `headerBackVisible: true` if the back button should still be shown alongside the custom left element.
- `headerTitle` is useful when the title needs custom typography or extra layout, but custom title elements do not animate with the native title transition.
- Use `headerBackground` for a gradient, image, or custom background view. For translucent native headers on iOS, prefer `headerTransparent: true` with `scrollEdgeEffects` for iOS 26+ or `headerBlurEffect` for earlier versions.
- Some behavior differs between iOS versions. On iOS 26+, `unstable_headerRightItems` can collapse into the system overflow menu when there is not enough space.
- Custom items with `type: 'custom'` in `unstable_headerRightItems` are not collapsed into the overflow menu.
- Labels are used when items collapse into the overflow menu, and for accessibility.
### Screen Presentations
Use the screen `presentation` option to control whether a screen is pushed normally or shown as a modal or sheet.
**Static API**
```tsx
const AppStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Compose: {
screen: ComposeScreen,
options: {
presentation: 'modal',
animation: 'slide_from_bottom',
},
},
},
});
```
**Dynamic API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen
name="Compose"
component={ComposeScreen}
options={{
presentation: 'modal',
animation: 'slide_from_bottom',
}}
/>
</Stack.Navigator>
);
}
```
- Use `card` for the default push presentation.
- Use `modal` for a standard modal presentation.
- Use `containedModal` for a current-context modal presentation on iOS and the default modal presentation on Android.
- Use `fullScreenModal` when the screen should take over the whole screen. On iOS, this presentation cannot be dismissed by gesture.
- Use `transparentModal` or `containedTransparentModal` when the previous screen should remain visible behind translucent content.
- Use `formSheet` when the design calls for a native sheet. Use [form-sheet.md](./form-sheet.md) for detents and platform-specific caveats.
- Use the `animation` option in the section below when the default transition does not fit the flow.
### Transition Animations
Use `animation` option to customize the transition animation.
**Static API**
```tsx
const AppStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Details: {
screen: DetailsScreen,
options: {
animation: 'fade_from_bottom',
animationDuration: 300,
},
},
},
});
```
**Dynamic API**
```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function AppStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{
animation: 'fade_from_bottom',
animationDuration: 300,
}}
/>
</Stack.Navigator>
);
}
```
- Supported `animation` values include `default`, `fade`, `fade_from_bottom`, `simple_push`, `slide_from_bottom`, `slide_from_right`, `slide_from_left`, `flip`, and `none`.
- `flip` requires `presentation: 'modal'` on iOS.
- `slide_from_right` and `slide_from_left` fall back to the default transition on iOS.
- `simple_push` removes the shadow and native header transition on iOS and falls back to the default transition on Android.
- Use `animationTypeForReplace: 'pop'` when `navigation.replace(...)` should feel like going back, such as auth or onboarding flows.
- Use `animationDuration` on iOS to tune `slide_from_bottom`, `fade_from_bottom`, `fade`, and `simple_push`. It does not apply to `default`, `flip`, or screens presented as `modal` or `formSheet`.
- Gesture-related transition options are only supported on iOS.
- Use `gestureEnabled` to disable swipe-to-dismiss when the animation should only run programmatically.
- Use `fullScreenGestureEnabled` to start the dismiss gesture anywhere on the screen. This uses `simple_push`-style behavior, and the default iOS transition cannot be matched due to platform limitations.
- Use `animationMatchesGesture` when the interactive dismiss gesture should follow the `animation` option. It does not affect screens presented modally.
- Use `fullScreenGestureShadowEnabled` to control the shadow shown during a full-screen dismiss gesture.
- On iOS, `gestureDirection: 'vertical'` implies `animation: 'slide_from_bottom'` together with full-screen dismissal gestures.
## Notes
- For scrollable content and `contentInsetAdjustmentBehavior="automatic"`, native stack needs it to be in the first-descendant chain — no views should be rendered before the scrollable view.
## Canonical Docs
- [Native Stack Navigator](https://reactnavigation.org/docs/native-stack-navigator)
- [Moving between screens](https://reactnavigation.org/docs/navigating)
- [Configuring the header bar](https://reactnavigation.org/docs/headers)
- [Opening a modal](https://reactnavigation.org/docs/modal)
## Related Skills
- [form-sheet.md](./form-sheet.md)
- [safe-areas.md](./safe-areas.md)
SHA-256: 734021ed72e83fc846e0dd19441e1ec0765db30d3cf1a21e5ba53b0ca53815aa