diff --git a/blog/2025-12-03-react-navigation-8.0-alpha.md b/blog/2025-12-03-react-navigation-8.0-alpha.md
new file mode 100644
index 00000000000..34f61460572
--- /dev/null
+++ b/blog/2025-12-03-react-navigation-8.0-alpha.md
@@ -0,0 +1,255 @@
+---
+title: React Navigation 8.0 Alpha
+authors: satya
+tags: [announcement]
+---
+
+We're excited to announce the first alpha release of React Navigation 8.0.
+
+This release focuses on improved TypeScript types for static configuration, native bottom tabs as the default, and various other improvements and new features. There are many more improvements planned for the final release.
+
+
+
+You can read the full list of changes in the [upgrade guide](/docs/8.x/upgrading-from-7.x). Here are some highlights:
+
+## Highlights
+
+### Native Bottom Tabs by default
+
+The Bottom Tab Navigator now uses native implementations by default on iOS and Android based on [`react-native-screens`](https://github.com/software-mansion/react-native-screens).
+
+This lets us provide a native look by default, such as the new liquid glass effect on iOS 26.
+
+
+
+
+
+
+
+
+
+
+
+We made the native implementation the default because we believe that the default experience should be as close to platform conventions as possible.
+
+However, we still include a custom JS based implementation in order to support Web and more customization options. You can switch to the JS implementation by passing the `implementation` prop as `custom` to the navigator.
+
+See [Bottom Tab Navigator docs](/docs/8.x/bottom-tab-navigator) for more details.
+
+### Ability to get `route`, `navigation`, and state for any parent screen
+
+One of the commonly requested features has been for screens to be able to access the params for parent screens, but this had a few problems:
+
+- Passing down params to child screens may lead to unnecessary re-renders when the parent params change, even when they are not needed by the child screen.
+- Since the param types are defined by the screen itself, having additional parent params would not be compatible with the existing type system.
+
+It was necessary to manually setup React Context to pass down parent params, which was cumbersome.
+
+The new screen name parameter in `useRoute` solves these problems. Now, you can access the parent route and its params directly by specifying the screen name:
+
+```js
+const route = useRoute('Profile');
+
+// Params for the 'Profile' screen
+console.log(route.params);
+```
+
+Similarly, you can get the `navigation` object for any parent screen by specifying the screen name in `useNavigation`:
+
+```js
+const navigation = useNavigation('Profile');
+
+// Navigation object for the 'Profile' screen
+console.log(navigation);
+```
+
+And you can get the navigation state for any parent screen by specifying the screen name in `useNavigationState`:
+
+```js
+const focusedRoute = useNavigationState(
+ 'Profile',
+ (state) => state.routes[state.index]
+);
+
+// Focused route for the navigator that contains the 'Profile' screen
+console.log(focusedRoute);
+```
+
+See [`useRoute`](/docs/8.x/use-route), [`useNavigation`](/docs/8.x/use-navigation), and [`useNavigationState`](/docs/8.x/use-navigation-state) for more details.
+
+### Better TypeScript types for static configuration
+
+In React Navigation 7, we introduced a static API to reduce boilerplate for deep linking and add automatic type inference. However, it still required manual type annotations in some cases and didn't express React Navigation's full capabilities.. So we had more work to do to get to a point that we're happy with.
+
+In this release, we've built upon the static API and reworked the type inference to solve many of these issues.
+
+Hooks like `useNavigation`, `useRoute`, and `useNavigationState` now automatically infer types based on the provided screen name:
+
+```js
+const navigation = useNavigation('Profile');
+
+// navigation is correctly typed as StackNavigationProp
+```
+
+The `navigation` object will now have proper types based on navigator nesting, and will include navigator specific methods such as `openDrawer` for drawer navigators or `push` for stack navigators without requiring manual type annotations.
+
+
+
+
+
+The `useRoute` hook now returns an union of all route types in the project when no screen name is provided, so it can be used in reusable components while still providing type safety.
+
+It will return the appropriate route type when a screen name is specified:
+
+```js
+const route = useRoute('Profile');
+
+// route is correctly typed as RouteProp
+```
+
+
+
+
+
+Similarly, the `useNavigationState` hook will infer the correct state type for the navigator that contains the specified screen:
+
+```js
+const focusedRoute = useNavigationState(
+ 'Profile',
+ (state) => state.routes[state.index]
+);
+
+// state is correctly typed as StackNavigationState
+```
+
+In addition, previously, the type of the `route` object couldn't be inferred in screen callbacks, listener callbacks, etc. This made it difficult to use route params in these callbacks.
+
+The new `createXScreen` helper functions address this:
+
+```js
+const Stack = createStackNavigator({
+ screens: {
+ Profile: createStackScreen({
+ screen: ProfileScreen,
+ options: ({ route }) => {
+ const userId = route.params.userId;
+
+ return {
+ title: `${userId}'s profile`
+ };
+ },
+ });
+ }
+});
+```
+
+Here, the type of `route.params` is correctly inferred based on the type annotation of `ProfileScreen`.
+
+Not only that, but it also infers types based on the path pattern in the `linking` configuration specified for the screen:
+
+```js
+const Stack = createStackNavigator({
+ screens: {
+ Profile: createStackScreen({
+ screen: ProfileScreen,
+ linking: {
+ path: 'profile/:userId',
+ parse: {
+ userId: (userId) => Number(userId),
+ },
+ },
+ });
+ }
+});
+```
+
+In this case, React Navigation can automatically infer that `userId` is a param of type `number` based on `:userId` in the path pattern and the return type of `userId` in the `parse` config. This is inspired by how [TanStack Router infers types based on the URL pattern](https://tanstack.com/router/latest/docs/framework/solid/decisions-on-dx#declaring-the-router-instance-for-type-inference).
+
+
+
+
+
+Each navigator exports its own helper function, e.g. `createNativeStackScreen` for Native Stack Navigator, `createBottomTabScreen` for Bottom Tab Navigator, `createDrawerScreen` for Drawer Navigator etc.
+
+With all of these improvements, it's technically possible to write an app without any manual type annotations for React Navigation, since we can infer the route type from path pattern and param parsing logic, and return correct type for `navigation` object, `route` object, and navigation state based on the screen name and navigation structure automatically.
+
+See [TypeScript docs](/docs/8.x/typescript) and [Static configuration docs](/docs/8.x/static-configuration) for more details.
+
+### Pushing history entries without pushing new screens
+
+Traditionally, the only way to add a new entry to the history stack was by pushing a new screen. But it's not always desirable, as it adds an entirely new instance of the screen component and shows transition animations.
+
+For many scenarios, we may want to add a new history entry without pushing a new screen. Such as:
+
+- A product listing page with filters, where changing filters should create a new history entry so that users can go back to previous filter states.
+- A screen with a custom modal component, where the modal is not a separate screen in the navigator, but its state should be reflected in the URL and history.
+
+The new `pushParams` API makes this possible. You can now push an entry to the history stack by adding new params without needing to push a new screen. Then the back button will update the screen to the previous params instead of going back a screen.
+
+
+
+
+
+
+This is especially important on the web, where users expect that changing certain UI states should create a new history entry, so that they can use the browser back and forward buttons to navigate through these states.
+
+See [`pushParams` docs](/docs/8.x/navigation-object#pushparams) for more details.
+
+### Support for `PlatformColor`, `DynamicColorIOS` and CSS custom properties in theme colors
+
+Previously, React Navigation's theming system only supported string color values. In this release, we've added support for platform-specific dynamic colors such as `PlatformColor` and `DynamicColorIOS` on native, as well as CSS custom properties on the web.
+
+This makes it easier to use system colors as well as share colors across native components and React Navigation components.
+
+```js
+const MyTheme = {
+ ...DefaultTheme,
+ colors: Platform.select({
+ ios: () => ({
+ primary: PlatformColor('systemRed'),
+ background: PlatformColor('systemGroupedBackground'),
+ // ...
+ }),
+ android: () => ({
+ primary: PlatformColor('@android:color/system_primary_light'),
+ // ...
+ }),
+ default: () => DefaultTheme.colors,
+ })(),
+};
+```
+
+However, there's one limitation: with string colors, React Navigation can automatically adjust colors in some scenarios (e.g. adjust the text color based on background color), which is not possible with dynamic colors. So it will fallback to pre-defined colors according to the theme in these cases.
+
+See [Themes docs](/docs/8.x/themes) for more details.
+
+## Plans for the final release
+
+This is just the first alpha release of React Navigation 8.0. Some of the plans for the final release include:
+
+- API to handle insets for navigation elements such as headers and tab bars
+- Navigation events in React Navigation Devtools
+- Accessibility improvements on Web by utilizing [`inert`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert)
+- [`Activity`](https://react.dev/reference/react/Activity) integration for inactive screens
+
+## Try it out
+
+If you'd like to try it out, add `@alpha` to the package you're installing. For example:
+
+```sh npm2yarn
+npm install @react-navigation/native@alpha @react-navigation/bottom-tabs@alpha
+```
+
+Your feedback is very important to us to ensure a smooth final release. If you encounter any issues or have any feedback or suggestions, please let us know on [GitHub issues](https://github.com/react-navigation/react-navigation/issues) or our [GitHub Discussions forum](https://github.com/react-navigation/react-navigation/discussions).
+
+## Special thanks
+
+React Navigation 8 would not have been possible without our amazing contributors.
+
+Thanks a lot to [Michał Osadnik](https://x.com/mosdnk), [Kacper Kafara](https://x.com/kafara_kacper), [Krzysztof Ligarski](https://github.com/kligarski), [Tomasz Boroń](https://github.com/t0maboro), [Konrad Michalik](https://github.com/kmichalikk), [Oskar Kwaśniewski](https://github.com/okwasniewski) and many others for their contributions to this release.
+
+## Sponsor us
+
+If React Navigation helps you to deliver value to your customers, it'd mean a lot if you could sponsor us. Sponsorships will help us to move more quickly towards our goal of building the best cross-platform navigation library and continue to provide timely support for bug reports in our GitHub issues.
+
+👉 [Visit our GitHub Sponsors page](https://github.com/sponsors/react-navigation) 👈
diff --git a/src/components/Pre.js b/src/components/Pre.js
index 70bf2be0de5..5d8faf8a65f 100644
--- a/src/components/Pre.js
+++ b/src/components/Pre.js
@@ -152,7 +152,11 @@ export default function Pre({
const version = activeVersion?.name;
if (version == null || versions[version] == null) {
- throw new Error(`Invalid version: ${version}`);
+ console.warn(
+ `No version information found for version "${version}", cannot resolve Snack dependencies automatically.`
+ );
+
+ return {children} ;
}
Object.assign(
diff --git a/src/css/custom.css b/src/css/custom.css
index 04f72074d69..ad288872fc2 100755
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -607,10 +607,6 @@ samp {
display: none;
}
-.markdown li > p {
- margin-bottom: 0;
-}
-
.video-player {
position: relative;
display: inline-block;
diff --git a/static/assets/blog/8.x/native-bottom-tabs-android.mp4 b/static/assets/blog/8.x/native-bottom-tabs-android.mp4
new file mode 100644
index 00000000000..c3f7999db7a
Binary files /dev/null and b/static/assets/blog/8.x/native-bottom-tabs-android.mp4 differ
diff --git a/static/assets/blog/8.x/native-bottom-tabs-ios.mp4 b/static/assets/blog/8.x/native-bottom-tabs-ios.mp4
new file mode 100644
index 00000000000..61532fcf9a7
Binary files /dev/null and b/static/assets/blog/8.x/native-bottom-tabs-ios.mp4 differ
diff --git a/static/assets/blog/8.x/params-types.mp4 b/static/assets/blog/8.x/params-types.mp4
new file mode 100644
index 00000000000..a34fd05b107
Binary files /dev/null and b/static/assets/blog/8.x/params-types.mp4 differ
diff --git a/static/assets/blog/8.x/push-params.mp4 b/static/assets/blog/8.x/push-params.mp4
new file mode 100644
index 00000000000..d6e95f119a1
Binary files /dev/null and b/static/assets/blog/8.x/push-params.mp4 differ
diff --git a/static/assets/blog/8.x/use-navigation.mp4 b/static/assets/blog/8.x/use-navigation.mp4
new file mode 100644
index 00000000000..ded618ee723
Binary files /dev/null and b/static/assets/blog/8.x/use-navigation.mp4 differ
diff --git a/static/assets/blog/8.x/use-route.mp4 b/static/assets/blog/8.x/use-route.mp4
new file mode 100644
index 00000000000..5efebbfc791
Binary files /dev/null and b/static/assets/blog/8.x/use-route.mp4 differ
diff --git a/versioned_docs/version-8.x/bottom-tab-navigator.md b/versioned_docs/version-8.x/bottom-tab-navigator.md
index cfaf4782454..2d4c0d24481 100755
--- a/versioned_docs/version-8.x/bottom-tab-navigator.md
+++ b/versioned_docs/version-8.x/bottom-tab-navigator.md
@@ -4,10 +4,14 @@ title: Bottom Tabs Navigator
sidebar_label: Bottom Tabs
---
-A simple tab bar on the bottom of the screen that lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.
+Bottom Tab Navigator displays a set of screens with a tab bar to switch between them.
-
+
+
+
+
+
## Installation
@@ -80,6 +84,52 @@ export default function App() {
In addition to the [common props](navigator.md#configuration) shared by all navigators, the bottom tab navigator accepts the following additional props:
+#### `implementation`
+
+The implementation to use for rendering the tab bar. Possible values:
+
+- `'native'` (default) - Uses native bottom tabs on iOS and Android. This allows matching the native design such as liquid glass effect on iOS 26.
+- `'custom'` - Uses a JavaScript-based implementation for the tab bar. Use this if you need more customization than what's possible with native tabs.
+
+
+
+
+```js
+createBottomTabNavigator({
+ implementation: 'custom',
+ // ...
+});
+```
+
+
+
+
+```js
+{/* ... */}
+```
+
+
+
+
+When using native tabs, some options behave differently:
+
+- `tabBarShowLabel` is replaced with `tabBarLabelVisibilityMode` which accepts:
+ - `"auto"` (default)
+ - `"selected"`
+ - `"labeled"` - same as `tabBarShowLabel: true`
+ - `"unlabeled"` - same as `tabBarShowLabel: false`
+- `tabBarLabel` only accepts a `string`
+- `tabBarIcon` accepts a function that returns an icon object
+
+:::note
+
+- The `native` implementation uses `UITabBarController` on iOS and `BottomNavigationView` on Android.
+- Liquid Glass effect on iOS 26+ requires your app to be built with Xcode 26 or above.
+- On Android, at most 5 tabs are supported with `native` implementation. This is a limitation of the underlying native component.
+- The `native` implementation requires React Native 0.79 or above. If you're using [Expo](https://expo.dev/), it requires SDK 53 or above.
+
+:::
+
#### `backBehavior`
This controls what happens when `goBack` is called in the navigator. This includes pressing the device's back button or back gesture on Android.
@@ -97,10 +147,14 @@ It supports the following values:
Boolean used to indicate whether inactive screens should be detached from the view hierarchy to save memory. This enables integration with [react-native-screens](https://github.com/software-mansion/react-native-screens). Defaults to `true`.
+Only supported with `custom` implementation.
+
#### `tabBar`
Function that returns a React element to display as the tab bar.
+Only supported with `custom` implementation.
+
The function receives an object containing the following properties as the argument:
- `state` - The state object for the tab navigator.
@@ -272,11 +326,61 @@ Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`
#### `tabBarLabel`
-Title string of a tab displayed in the tab bar or a function that given `{ focused: boolean, color: string }` returns a React.Node, to display in tab bar. When undefined, scene `title` is used. To hide, see `tabBarShowLabel`.
+Title string of a tab displayed in the tab bar. When undefined, scene `title` is used. To hide, see [`tabBarLabelVisibilityMode`](#tabbarlabelvisibilitymode).
+
+Overrides the label provided by [`tabBarSystemItem`](#tabbarsystemitem) on iOS.
+
+#### `tabBarSystemItem`
+
+Uses iOS built-in tab bar items with standard iOS styling and localized titles. Supported values:
+
+- `bookmarks`
+- `contacts`
+- `downloads`
+- `favorites`
+- `featured`
+- `history`
+- `more`
+- `mostRecent`
+- `mostViewed`
+- `recents`
+- `search`
+- `topRated`
+
+Only supported with `native` implementation on iOS.
+
+The [`tabBarIcon`](#tabbaricon) and [`tabBarLabel`](#tabbarlabel) options will override the icon and label from the system item. If you want to keep the system behavior on iOS, but need to provide icon and label for other platforms, use `Platform.OS` or `Platform.select` to conditionally set `undefined` for `tabBarIcon` and `tabBarLabel` on iOS.
+
+##### Search tab on iOS 26+
+
+The `tabBarSystemItem` option has special styling and behavior when set to `search` on iOS 26+.
+
+Additionally, when the `search` tab is selected, the tab bar transforms into a search field if the screen in the tab navigator or a nested [native stack navigator](native-stack-navigator.md) has [`headerSearchBarOptions`](native-stack-navigator.md#headersearchbaroptions) configured and the native header is shown with [`headerShown: true`](native-stack-navigator.md#headershown). This won't work if a custom header is provided with the `header` option.
+
+Example:
+
+```js
+tabBarSystemItem: 'search',
+headerShown: true,
+headerSearchBarOptions: {
+ placeholder: 'Search',
+},
+```
+
+
+
+
-#### `tabBarShowLabel`
+#### `tabBarLabelVisibilityMode`
-Whether the tab label should be visible. Defaults to `true`.
+The label visibility mode for the tab bar items. Supported values:
+
+- `auto` - decided based on platform and implementation (default)
+- `labeled` - labels are always shown
+- `unlabeled` - labels are never shown
+- `selected` - labels shown only for selected tab (only supported on Android with `native` implementation)
+
+Supported on all platforms with `custom` implementation. Only supported on Android with `native` implementation.
#### `tabBarLabelPosition`
@@ -284,15 +388,29 @@ Whether the label is shown below the icon or beside the icon.
By default, the position is chosen automatically based on device width.
+Only supported with `custom` implementation.
+
- `below-icon`: the label is shown below the icon (typical for iPhones)
- `beside-icon` the label is shown next to the icon (typical for iPad)
+#### `tabBarAllowFontScaling`
+
+Whether label font should scale to respect Text Size accessibility settings. Defaults to `true`.
+
+Only supported with `custom` implementation.
+
#### `tabBarLabelStyle`
-Style object for the tab label.
+Style object for the tab label. Supported properties:
+
+- `fontFamily`
+- `fontSize`
+- `fontWeight`
+- `fontStyle`
+
Example:
@@ -309,10 +427,85 @@ Example:
Function that given `{ focused: boolean, color: string, size: number }` returns a React.Node, to display in the tab bar.
+With `native` implementation, you can pass an icon object directly instead of a function. A React element is only supported with `custom` implementation.
+
+It overrides the icon provided by [`tabBarSystemItem`](#tabbarsystemitem) on iOS.
+
+The icon can be of following types with `native` implementation:
+
+- Local image - Supported on iOS and Android
+
+ ```js
+ tabBarIcon: {
+ type: 'image',
+ source: require('./path/to/icon.png'),
+ }
+ ```
+
+ On iOS, you can additionally pass a `tinted` property to control whether the icon should be tinted with the active/inactive color:
+
+ ```js
+ tabBarIcon: {
+ type: 'image',
+ source: require('./path/to/icon.png'),
+ tinted: false,
+ }
+ ```
+
+ The image is tinted by default.
+
+- [SF Symbols](https://developer.apple.com/sf-symbols/) name - Supported on iOS
+
+ ```js
+ tabBarIcon: {
+ type: 'sfSymbol',
+ name: 'heart',
+ }
+ ```
+
+- [Drawable resource](https://developer.android.com/guide/topics/resources/drawable-resource) name - Supported on Android
+
+ ```js
+ tabBarIcon: {
+ type: 'drawableResource',
+ name: 'sunny',
+ }
+ ```
+
+To render different icons for active and inactive states with `native` implementation, you can use a function:
+
+```js
+tabBarIcon: ({ focused }) => {
+ return {
+ type: 'sfSymbol',
+ name: focused ? 'heart.fill' : 'heart',
+ };
+},
+```
+
+This is only supported on iOS. On Android, the icon specified for inactive state will be used for both active and inactive states.
+
+To provide different icons for different platforms, you can use [`Platform.select`](https://reactnative.dev/docs/platform-specific-code):
+
+```js
+tabBarIcon: Platform.select({
+ ios: {
+ type: 'sfSymbol',
+ name: 'heart',
+ },
+ android: {
+ type: 'drawableResource',
+ name: 'heart_icon',
+ },
+});
+```
+
#### `tabBarIconStyle`
Style object for the tab icon.
+Only supported with `custom` implementation.
+
#### `tabBarBadge`
Text to show in a badge on the tab icon. Accepts a `string` or a `number`.
@@ -321,7 +514,12 @@ Text to show in a badge on the tab icon. Accepts a `string` or a `number`.
#### `tabBarBadgeStyle`
-Style for the badge on the tab icon. You can specify a background color or text color here.
+Style for the badge on the tab icon. Supported properties:
+
+- `backgroundColor`
+- `color`
+
+Supported on all platforms with `custom` implementation. Only supported with `native` implementation on Android.
@@ -338,10 +536,14 @@ Example:
Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.
+Only supported with `custom` implementation.
+
#### `tabBarButton`
Function which returns a React element to render as the tab bar button. It wraps the icon and label. Renders `Pressable` by default.
+Only supported with `custom` implementation.
+
You can specify a custom implementation here:
```js
@@ -352,6 +554,8 @@ tabBarButton: (props) => ;
ID to locate this tab button in tests.
+Only supported with `custom` implementation.
+
#### `tabBarActiveTintColor`
Color for the icon and label in the active tab.
@@ -362,27 +566,80 @@ Color for the icon and label in the active tab.
Color for the icon and label in the inactive tabs.
+#### `tabBarActiveIndicatorColor`
+
+Background color of the active indicator.
+
+Only supported with `native` implementation on Android.
+
+#### `tabBarActiveIndicatorEnabled`
+
+Whether the active indicator should be used. Defaults to `true`.
+
+Only supported with `native` implementation on Android.
+
+#### `tabBarRippleColor`
+
+Color of the ripple effect when pressing a tab.
+
+Only supported with `native` implementation on Android.
+
#### `tabBarActiveBackgroundColor`
Background color for the active tab.
+Only supported with `custom` implementation.
+
#### `tabBarInactiveBackgroundColor`
Background color for the inactive tabs.
+Only supported with `custom` implementation.
+
#### `tabBarHideOnKeyboard`
Whether the tab bar is hidden when the keyboard opens. Defaults to `false`.
+Only supported with `custom` implementation.
+
+#### `tabBarVisibilityAnimationConfig`
+
+Animation config for showing and hiding the tab bar when the keyboard is shown/hidden.
+
+Only supported with `custom` implementation.
+
+Example:
+
+```js
+tabBarVisibilityAnimationConfig: {
+ show: {
+ animation: 'timing',
+ config: {
+ duration: 200,
+ },
+ },
+ hide: {
+ animation: 'timing',
+ config: {
+ duration: 100,
+ },
+ },
+},
+```
+
#### `tabBarItemStyle`
Style object for the tab item container.
+Only supported with `custom` implementation.
+
#### `tabBarStyle`
Style object for the tab bar. You can configure styles such as background color here.
-To show your screen under the tab bar, you can set the `position` style to absolute:
+With `custom` implementation, this accepts any style properties. With `native` implementation, only `backgroundColor` and `shadowColor` (iOS 18 and below) are supported.
+
+To show your screen under the tab bar, you can set the `position` style to absolute (only with `custom` implementation):
```js
@@ -498,10 +761,77 @@ Variant of the tab bar. Available values are:
- `uikit` (Default) - The tab bar will be styled according to the iOS UIKit guidelines.
- `material` - The tab bar will be styled according to the Material Design guidelines.
+Only supported with `custom` implementation.
+
The `material` variant is currently only supported when the [`tabBarPosition`](#tabbarposition) is set to `left` or `right`.

+#### `tabBarBlurEffect`
+
+Blur effect applied to the tab bar on iOS 18 and lower when tab screen is selected.
+
+Supported values:
+
+- `none` - no blur effect
+- `systemDefault` - default blur effect applied by the system
+- `extraLight`
+- `light`
+- `dark`
+- `regular`
+- `prominent`
+- `systemUltraThinMaterial`
+- `systemThinMaterial`
+- `systemMaterial`
+- `systemThickMaterial`
+- `systemChromeMaterial`
+- `systemUltraThinMaterialLight`
+- `systemThinMaterialLight`
+- `systemMaterialLight`
+- `systemThickMaterialLight`
+- `systemChromeMaterialLight`
+- `systemUltraThinMaterialDark`
+- `systemThinMaterialDark`
+- `systemMaterialDark`
+- `systemThickMaterialDark`
+- `systemChromeMaterialDark`
+
+Defaults to `systemDefault`.
+
+Only supported with `native` implementation on iOS 18 and below.
+
+#### `tabBarControllerMode`
+
+The display mode for the tab bar. Supported values:
+
+- `auto` - the system sets the display mode based on the tab's content
+- `tabBar` - the system displays the content only as a tab bar
+- `tabSidebar` - the tab bar is displayed as a sidebar
+
+Supported on all platforms with `custom` implementation. By default:
+
+- `tabBar` is positioned at the bottom
+- `tabSidebar` is positioned on the left (LTR) or right (RTL)
+
+The [`tabBarPosition`](#tabbarposition) option can be used to override this in `custom` implementation.
+
+Supported on iOS 18 and above with `native` implementation. Not supported on tvOS.
+
+#### `tabBarMinimizeBehavior`
+
+The minimize behavior for the tab bar. Supported values:
+
+- `auto` - resolves to the system default minimize behavior
+- `never` - the tab bar does not minimize
+- `onScrollDown` - the tab bar minimizes when scrolling down and expands when scrolling back up
+- `onScrollUp` - the tab bar minimizes when scrolling up and expands when scrolling back down
+
+Only supported with `native` implementation on iOS 26 and above.
+
+
+
+
+
#### `lazy`
Whether this screen should render only after the first time it's accessed. Defaults to `true`. Set it to `false` if you want to render the screen on the initial render of the navigator.
@@ -525,7 +855,9 @@ Style object for the component wrapping the screen content.
### Header related options
-You can find the list of header related options [here](elements.md#header). These [options](screen-options.md) can be specified under `screenOptions` prop of `Tab.Navigator` or `options` prop of `Tab.Screen`. You don't have to be using `@react-navigation/elements` directly to use these options, they are just documented in that page.
+The navigator does not show a header by default. It renders a native stack header if `headerShown` is set to `true` in the screen options explicitly, or if a custom header is provided with the `header` option.
+
+It supports all of the [header related options supported in `@react-navigation/native-stack`](native-stack-navigator.md#header-related-options) apart from the options related to the back button (prefixed with `headerBack`).
In addition to those, the following options are also supported in bottom tabs:
@@ -587,7 +919,13 @@ This event is fired when the user presses the tab button for the current screen
- If the screen for the tab renders a scroll view, you can use [`useScrollToTop`](use-scroll-to-top.md) to scroll it to top
- If the screen for the tab renders a stack navigator, a `popToTop` action is performed on the stack
-To prevent the default behavior, you can call `event.preventDefault`:
+To prevent the default behavior, you can call `event.preventDefault`.
+
+:::note
+
+Calling `event.preventDefault` is only supported with the `custom` implementation. The default behavior cannot be prevented with the `native` implementation.
+
+:::
```js name="Tab Press Event" snack static2dynamic
import * as React from 'react';
@@ -659,6 +997,8 @@ By default, tabs are rendered lazily. So if you add a listener inside a screen c
This event is fired when the user presses the tab button for the current screen in the tab bar for an extended period. If you have a custom tab bar, make sure to emit this event.
+Only supported with the `custom` implementation.
+
Example:
```js
@@ -671,6 +1011,38 @@ React.useEffect(() => {
}, [navigation]);
```
+#### `transitionStart`
+
+This event is fired when a transition animation starts when switching tabs.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('transitionStart', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+#### `transitionEnd`
+
+This event is fired when a transition animation ends when switching tabs.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('transitionEnd', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
### Helpers
The tab navigator adds the following methods to the navigation object:
@@ -779,6 +1151,12 @@ import { BottomTabBarHeightContext } from '@react-navigation/bottom-tabs';
By default, switching between tabs doesn't have any animation. You can specify the `animation` option to customize the transition animation.
+:::note
+
+Customizing animations are only supported with the `custom` implementation.
+
+:::
+
Supported values for `animation` are:
- `fade` - Cross-fade animation for the screen transition where the new screen fades in and the old screen fades out.
diff --git a/versioned_docs/version-8.x/configuring-links.md b/versioned_docs/version-8.x/configuring-links.md
index 7b98cbee23c..835cf623fb2 100644
--- a/versioned_docs/version-8.x/configuring-links.md
+++ b/versioned_docs/version-8.x/configuring-links.md
@@ -13,7 +13,7 @@ In this guide, we will configure React Navigation to handle external links. This
2. Enable URL integration in browser when using on web
3. Use [` `](link.md) or [`useLinkTo`](use-link-to.md) to navigate using paths.
-Make sure that you have [configured deep links](deep-linking.md) in your app before proceeding. If you have an Android or iOS app, remember to specify the [`prefixes`](navigation-container.md#linkingprefixes) option.
+Make sure that you have [configured deep links](deep-linking.md) in your app before proceeding.
@@ -23,20 +23,14 @@ The [`Navigation`](static-configuration.md#createstaticnavigation) component acc
```js
import { createStaticNavigation } from '@react-navigation/native';
-// highlight-start
-const linking = {
- enabled: 'auto' /* Automatically generate paths for all screens */,
- prefixes: [
- /* your linking prefixes */
- ],
-};
-// highlight-end
-
function App() {
return (
Loading...}
/>
);
@@ -55,9 +49,6 @@ import { NavigationContainer } from '@react-navigation/native';
// highlight-start
const linking = {
- prefixes: [
- /* your linking prefixes */
- ],
config: {
/* configuration for matching screens with paths */
},
@@ -80,19 +71,15 @@ function App() {
-When you specify the `linking` prop, React Navigation will handle incoming links automatically. On Android and iOS, it'll use React Native's [`Linking` module](https://reactnative.dev/docs/linking) to handle incoming links, both when the app was opened with the link, and when new links are received when the app is open. On the Web, it'll use the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to sync the URL with the browser.
-
-:::warning
-
-Currently there seems to be bug ([facebook/react-native#25675](https://github.com/facebook/react-native/issues/25675)) which results in it never resolving on Android. We add a timeout to avoid getting stuck forever, but it means that the link might not be handled in some cases.
+When you specify the `linking` prop, React Navigation will handle incoming links automatically.
-:::
+On Android and iOS, it'll use React Native's [`Linking` module](https://reactnative.dev/docs/linking) to handle incoming deep links and universal links, both when the app was opened with the link, and when new links are received when the app is open. On the Web, it'll use the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to sync the URL with the browser.
You can also pass a [`fallback`](navigation-container.md#fallback) prop that controls what's displayed when React Navigation is trying to resolve the initial deep link URL.
## Prefixes
-The `prefixes` option can be used to specify custom schemes (e.g. `example://`) as well as host & domain names (e.g. `https://example.com`) if you have configured [Universal Links](https://developer.apple.com/ios/universal-links/) or [Android App Links](https://developer.android.com/training/app-links).
+The `prefixes` option can be optionally used to specify custom schemes (e.g. `example://`) as well as host & domain names (e.g. `https://example.com`) if you have configured [Universal Links](https://developer.apple.com/ios/universal-links/) or [Android App Links](https://developer.android.com/training/app-links).
For example:
@@ -102,7 +89,9 @@ const linking = {
};
```
-Note that the `prefixes` option is not supported on Web. The host & domain names will be automatically determined from the Website URL in the browser. If your app runs only on Web, then you can omit this option from the config.
+If not specified, it defaults to `['*']`, which will match any host starting with `http`, `https`, and custom schemes such as `myapp://`. You only need to specify `prefixes` if you're using **Expo Go** or want to restrict the URLs your app handles.
+
+Note that the `prefixes` option has no effect on Web. The host & domain names will be automatically determined from the Website URL in the browser.
### Multiple subdomains
diff --git a/versioned_docs/version-8.x/custom-navigators.md b/versioned_docs/version-8.x/custom-navigators.md
index e50e11714d4..55d758c3bd7 100755
--- a/versioned_docs/version-8.x/custom-navigators.md
+++ b/versioned_docs/version-8.x/custom-navigators.md
@@ -4,6 +4,9 @@ title: Custom navigators
sidebar_label: Custom navigators
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
In essence, a navigator is a React component that takes a set of screens and options, and renders them based on its [navigation state](navigation-state.md), generally with additional UI such as headers, tab bars, or drawers.
React Navigation provides a few built-in navigators, but they might not always fit your needs if you want a very custom behavior or UI. In such cases, you can build your own custom navigators using React Navigation's APIs.
@@ -19,7 +22,7 @@ The navigator component then uses this state to layout the screens appropriately
A very basic example looks like this:
```js
-function MyStackNavigator(props) {
+function MyNavigator(props) {
const { state, descriptors, NavigationContent } = useNavigationBuilder(
StackRouter,
props
@@ -31,14 +34,14 @@ function MyStackNavigator(props) {
return {descriptor.render()} ;
}
-export const createMyStackNavigator = createNavigatorFactory(MyStackNavigator);
+export const createMyNavigator = createNavigatorFactory(MyNavigator);
```
Now, we have an already working navigator, even though it doesn't do anything special yet.
Let's break this down:
-- We define a `MyNavigator` component that contains our navigator logic. This is the component that's rendered when you render `` in your app with the `createMyStackNavigator` factory function.
+- We define a `MyNavigator` component that contains our navigator logic. This is the component that's rendered when you render the navigator in your app with the `createMyNavigator` factory function.
- We use the `useNavigationBuilder` hook and pass it [`StackRouter`](custom-routers.md#built-in-routers), which would make our navigator behave like a stack navigator. Any other router such as `TabRouter`, `DrawerRouter`, or a custom router can be used here as well.
- The hook returns the [navigation state](navigation-state.md) in the `state` property. This is the current state of the navigator. There's also a `descriptors` object which contains the data and helpers for each screen in the navigator.
- We get the focused route from the state with `state.routes[state.index]` - as `state.index` is the index of the currently focused route in the `state.routes` array.
@@ -180,24 +183,27 @@ We can also do `export const createMyNavigator = createNavigatorFactory(MyNaviga
Then it can be used like this:
-```js
+```js static2dynamic
+import { createStaticNavigation } from '@react-navigation/native';
import { createMyNavigator } from './myNavigator';
-const My = createMyNavigator();
+const MyTabs = createMyNavigator({
+ screens: {
+ Home: HomeScreen,
+ Feed: FeedScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTabs);
function App() {
- return (
-
-
-
-
- );
+ return ;
}
```
## Type-checking navigators
-To type-check navigators, we need to provide 3 types:
+To type-check navigators, we need to provide few types:
- Type of the props accepted by the view
- Type of supported screen options
@@ -222,6 +228,7 @@ import {
type NavigatorTypeBagBase,
type ParamListBase,
type StaticConfig,
+ type StaticScreenConfig,
type TabActionHelpers,
type TabNavigationState,
TabRouter,
@@ -337,29 +344,55 @@ function TabNavigator({ tabBarStyle, contentStyle, ...rest }: Props) {
);
}
-// The factory function with generic types for type-inference
+// Types required for type-checking the navigator
+type MyTabTypeBag = {
+ ParamList: ParamList;
+ State: TabNavigationState;
+ ScreenOptions: TabNavigationOptions;
+ EventMap: TabNavigationEventMap;
+ NavigationList: {
+ [RouteName in keyof ParamList]: TabNavigationProp;
+ };
+ Navigator: typeof TabNavigator;
+};
+
+// The factory function with overloads for static and dynamic configuration
export function createMyNavigator<
const ParamList extends ParamListBase,
- const NavigatorID extends string | undefined = undefined,
- const TypeBag extends NavigatorTypeBagBase = {
- ParamList: ParamList;
- NavigatorID: NavigatorID;
- State: TabNavigationState;
- ScreenOptions: TabNavigationOptions;
- EventMap: TabNavigationEventMap;
- NavigationList: {
- [RouteName in keyof ParamList]: TabNavigationProp<
- ParamList,
- RouteName,
- NavigatorID
- >;
- };
- Navigator: typeof TabNavigator;
- },
- const Config extends StaticConfig = StaticConfig,
->(config?: Config): TypedNavigator {
+>(): TypedNavigator, undefined>;
+export function createMyNavigator<
+ const Config extends StaticConfig>,
+>(
+ config: Config
+): TypedNavigator>, Config>;
+export function createMyNavigator(config?: unknown) {
return createNavigatorFactory(TabNavigator)(config);
}
+
+// Helper function for creating screen config with proper types for static configuration
+export function createMyScreen<
+ const Linking extends StaticScreenConfigLinking,
+ const Screen extends StaticScreenConfigScreen,
+>(
+ config: StaticScreenConfigInput<
+ Linking,
+ Screen,
+ TabNavigationState,
+ MyNavigationOptions,
+ MyNavigationEventMap,
+ MyNavigationProp
+ >
+): StaticScreenConfigResult<
+ Linking,
+ Screen,
+ TabNavigationState,
+ MyNavigationOptions,
+ MyNavigationEventMap,
+ MyNavigationProp
+> {
+ // @ts-expect-error: there is some issue with the generic inference here
+ return config;
+}
```
## Extending Navigators
@@ -376,7 +409,6 @@ import {
import { BottomTabView } from '@react-navigation/bottom-tabs';
function BottomTabNavigator({
- id,
initialRouteName,
children,
layout,
@@ -388,7 +420,6 @@ function BottomTabNavigator({
}) {
const { state, descriptors, navigation, NavigationContent } =
useNavigationBuilder(TabRouter, {
- id,
initialRouteName,
children,
layout,
@@ -442,7 +473,7 @@ const { state, descriptors, navigation, NavigationContent } =
Customizing built-in navigators like this is an advanced use case and generally not necessary. Consider alternatives such as:
- [`layout`](navigator.md#layout) prop on navigators to add a wrapper around the navigator
-- [`UNSTABLE_router`](navigator.md#router) prop on navigators to customize the router behavior
+- [`router`](navigator.md#router) prop on navigators to customize the router behavior
Also refer to the navigator's documentation to see if any existing API meets your needs.
diff --git a/versioned_docs/version-8.x/drawer-navigator.md b/versioned_docs/version-8.x/drawer-navigator.md
index 594f49b0c16..0feb5e44dbb 100644
--- a/versioned_docs/version-8.x/drawer-navigator.md
+++ b/versioned_docs/version-8.x/drawer-navigator.md
@@ -450,7 +450,7 @@ function MyDrawer() {
screenOptions={{
drawerType: isLargeScreen ? 'permanent' : 'back',
drawerStyle: isLargeScreen ? null : { width: '100%' },
- overlayColor: 'transparent',
+ overlayStyle: { backgroundColor: 'transparent' },
}}
>
{/* Screens */}
@@ -483,9 +483,15 @@ Supported values:
- `none`
-#### `overlayColor`
+#### `overlayStyle`
-Color overlay to be displayed on top of the content view when drawer gets open. The opacity is animated from `0` to `1` when the drawer opens.
+Style for the overlay on top of the content view when drawer gets open. You can use this to customize the overlay color, opacity, and other properties:
+
+```js
+overlayStyle: {
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
+}
+```
diff --git a/versioned_docs/version-8.x/elements.md b/versioned_docs/version-8.x/elements.md
index 688f45b88b4..98f38b55ce7 100644
--- a/versioned_docs/version-8.x/elements.md
+++ b/versioned_docs/version-8.x/elements.md
@@ -354,7 +354,7 @@ It can contain the following properties:
- `cancelButtonText`: Text to be used instead of default `Cancel` button text (iOS only).
- `inputType`: Type of the input. Possible values: `text`, `phone`, `number`, `email`.
- `onBlur`: Callback that gets called when search input has lost focus.
-- `onChangeText`: Callback that gets called when the text changes.
+- `onChange`: Callback that gets called when the text changes.
- `onClose`: Callback that gets called when search input is closed.
- `onFocus`: Callback that gets called when search input has received focus.
- `placeholder`: Text displayed when search input is empty.
@@ -364,7 +364,9 @@ React.useLayoutEffect(() => {
navigation.setOptions({
headerSearchBarOptions: {
placeholder: 'Search',
- onChangeText: (text) => {
+ onChange: (event) => {
+ const text = event.nativeEvent.text;
+
// Do something
},
},
@@ -730,14 +732,33 @@ Usage:
Home
```
-### `ResourceSavingView`
+### `Badge`
+
+A component that renders a badge, typically used to show a count or status indicator on tab icons.
+
+It accepts the following props:
-A component which aids in improving performance for inactive screens by utilizing [`removeClippedSubviews`](https://reactnative.dev/docs/view#removeclippedsubviews). It accepts a `visible` prop to indicate whether a screen should be clipped.
+- `visible` - Whether the badge is visible.
+- `children` - Content of the badge (string or number).
+- `size` - Size of the badge. Defaults to `18`.
+- `style` - Style object for the badge.
Usage:
-```js
-{/* Content */}
+```jsx
+5
+```
+
+### `Text`
+
+A themed text component that automatically applies the theme's text color and font styles.
+
+It accepts the same props as React Native's [`Text`](https://reactnative.dev/docs/text) component.
+
+Usage:
+
+```jsx
+Hello World
```
## Utilities
@@ -818,12 +839,39 @@ import { useHeaderHeight } from '@react-navigation/elements';
const headerHeight = useHeaderHeight();
```
+### `useFrameSize`
+
+Hook that returns the size of the frame of the parent navigator. It accepts a selector function which receives the frame dimensions and returns a value:
+
+```js
+import { useFrameSize } from '@react-navigation/elements';
+
+// ...
+
+const isLandscape = useFrameSize((frame) => frame.width > frame.height);
+```
+
+The selector ensures that the component only re-renders when we need to.
+
### `getDefaultHeaderHeight`
-Helper that returns the default header height. It takes the following parameters:
+Helper that returns the default header height. It takes an object with the following properties:
+
+- `landscape` - Whether the device is in landscape orientation.
+- `modalPresentation` - Whether the screen is presented as a modal.
+- `topInset` - The height of the top inset (status bar height).
-- `layout` - Layout of the screen, i.e. an object containing `height` and `width` properties.
-- `statusBarHeight` - height of the statusbar
+```js
+import { getDefaultHeaderHeight } from '@react-navigation/elements';
+
+// ...
+
+const headerHeight = getDefaultHeaderHeight({
+ landscape: false,
+ modalPresentation: false,
+ topInset: statusBarHeight,
+});
+```
### `getHeaderTitle`
@@ -832,16 +880,33 @@ Helper that returns the title text to use in header. It takes the following para
- `options` - The options object of the screen.
- `fallback` - Fallback title string if no title was found in options.
-### `useFrameSize`
+### `getLabel`
-Hook that returns the size of the frame of the parent navigator. It accepts a selector function which receives the frame dimensions and returns a value:
+Helper that returns the label text to use. It takes the following parameters:
+
+- `options` - An object with optional `label` and `title` properties.
+- `fallback` - Fallback label string if no label or title was found in options.
```js
-import { useFrameSize } from '@react-navigation/elements';
+import { getLabel } from '@react-navigation/elements';
// ...
-const isLandscape = useFrameSize((frame) => frame.width > frame.height);
+const label = getLabel(options, route.name);
```
-The selector ensures that the component only re-renders when we need to.
+### `getDefaultSidebarWidth`
+
+Helper that returns the default sidebar width based on the screen dimensions. It follows Material Design 3 guidelines for navigation drawer specs.
+
+It takes an object with the following property:
+
+- `width` - The width of the screen.
+
+```js
+import { getDefaultSidebarWidth } from '@react-navigation/elements';
+
+// ...
+
+const sidebarWidth = getDefaultSidebarWidth({ width: screenWidth });
+```
diff --git a/versioned_docs/version-8.x/function-after-focusing-screen.md b/versioned_docs/version-8.x/function-after-focusing-screen.md
index 26528f8eebb..39add70e42a 100755
--- a/versioned_docs/version-8.x/function-after-focusing-screen.md
+++ b/versioned_docs/version-8.x/function-after-focusing-screen.md
@@ -36,7 +36,10 @@ import {
useNavigation,
createStaticNavigation,
} from '@react-navigation/native';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ createBottomTabNavigator,
+ createBottomTabScreen,
+} from '@react-navigation/bottom-tabs';
// codeblock-focus-start
function ProfileScreen() {
@@ -63,8 +66,12 @@ function HomeScreen() {
const MyTabs = createBottomTabNavigator({
screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
+ Home: createBottomTabScreen({
+ screen: HomeScreen,
+ }),
+ Profile: createBottomTabScreen({
+ screen: ProfileScreen,
+ }),
},
});
@@ -147,7 +154,10 @@ import {
useFocusEffect,
createStaticNavigation,
} from '@react-navigation/native';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ createBottomTabNavigator,
+ createBottomTabScreen,
+} from '@react-navigation/bottom-tabs';
// codeblock-focus-start
function ProfileScreen() {
@@ -173,8 +183,12 @@ function HomeScreen() {
const MyTabs = createBottomTabNavigator({
screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
+ Home: createBottomTabScreen({
+ screen: HomeScreen,
+ }),
+ Profile: createBottomTabScreen({
+ screen: ProfileScreen,
+ }),
},
});
const Navigation = createStaticNavigation(MyTabs);
@@ -249,7 +263,10 @@ The `useIsFocused` hook will cause our component to re-render when we focus and
import * as React from 'react';
import { View, Text } from 'react-native';
import { useIsFocused, createStaticNavigation } from '@react-navigation/native';
-import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+import {
+ createMaterialTopTabNavigator,
+ createMaterialTopTabScreen,
+} from '@react-navigation/material-top-tabs';
// codeblock-focus-start
function ProfileScreen() {
@@ -272,8 +289,12 @@ function HomeScreen() {
const MyTabs = createMaterialTopTabNavigator({
screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
+ Home: createMaterialTopTabScreen({
+ screen: HomeScreen,
+ }),
+ Profile: createMaterialTopTabScreen({
+ screen: ProfileScreen,
+ }),
},
});
diff --git a/versioned_docs/version-8.x/getting-started.md b/versioned_docs/version-8.x/getting-started.md
index 9aa30834237..66272242552 100755
--- a/versioned_docs/version-8.x/getting-started.md
+++ b/versioned_docs/version-8.x/getting-started.md
@@ -22,9 +22,10 @@ Here are some resources to help you out:
## Minimum requirements
-- `react-native` >= 0.72.0
-- `expo` >= 52 (if you use [Expo Go](https://expo.dev/go))
-- `typescript` >= 5.0.0 (if you use TypeScript)
+- `react-native` >= 0.81
+- `expo` >= 54 (if you use [Expo Go](https://expo.dev/go))
+- `typescript` >= 5.9.2 (if you use TypeScript)
+- `react-native-web` >= 0.21.0 (if you support Web)
## Starter template
diff --git a/versioned_docs/version-8.x/header-buttons.md b/versioned_docs/version-8.x/header-buttons.md
index 6de8a233717..902c80db0b4 100755
--- a/versioned_docs/version-8.x/header-buttons.md
+++ b/versioned_docs/version-8.x/header-buttons.md
@@ -13,14 +13,14 @@ Now that we know how to customize the look of our headers, let's make them senti
The most common way to interact with a header is by tapping on a button either to the left or the right of the title. Let's add a button to the right side of the header (one of the most difficult places to touch on your entire screen, depending on finger and phone size, but also a normal place to put buttons).
-
-
-
-```js name="Header button" snack
+```js name="Header button" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
@@ -34,7 +34,7 @@ function HomeScreen() {
// codeblock-focus-start
const MyStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
// highlight-start
@@ -43,7 +43,7 @@ const MyStack = createNativeStackNavigator({
),
// highlight-end
},
- },
+ }),
},
});
// codeblock-focus-end
@@ -55,58 +55,6 @@ export default function App() {
}
```
-
-
-
-```js name="Header button" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function MyStack() {
- return (
-
- (
- alert('This is a button!')}>Info
- ),
- // highlight-end
- }}
- />
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-

When we define our button this way, the `this` variable in `options` is _not_ the `HomeScreen` instance, so you can't call `setState` or any instance methods on it. This is pretty important because it's common to want the buttons in your header to interact with the screen that the header belongs to. So, we will look how to do this next.
@@ -121,22 +69,22 @@ Note that a community-developed library for rendering buttons in the header with
In some cases, components in the header need to interact with the screen component. For this use case, we need to use `navigation.setOptions` to update our options. By using `navigation.setOptions` inside the screen component, we get access to screen's props, state, context etc.
-
-
-
-```js name="Header button" snack
+```js name="Header button" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
// codeblock-focus-start
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
const [count, setCount] = React.useState(0);
React.useEffect(() => {
@@ -156,14 +104,14 @@ function HomeScreen() {
const MyStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
// Add a placeholder button without the `onPress` to avoid flicker
// highlight-next-line
headerRight: () => Update count ,
},
- },
+ }),
},
});
// codeblock-focus-end
@@ -175,67 +123,6 @@ export default function App() {
}
```
-
-
-
-```js name="Header button" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function HomeScreen() {
- const navigation = useNavigation();
- const [count, setCount] = React.useState(0);
-
- React.useEffect(() => {
- // Use `setOptions` to update the button that we previously specified
- // Now the button includes an `onPress` handler to update the count
- // highlight-start
- navigation.setOptions({
- headerRight: () => (
- setCount((c) => c + 1)}>Update count
- ),
- });
- // highlight-end
- }, [navigation]);
-
- return Count: {count} ;
-}
-
-function MyStack() {
- return (
-
- Update count ,
- }}
- />
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
diff --git a/versioned_docs/version-8.x/headers.md b/versioned_docs/version-8.x/headers.md
index 04f18811603..c7759920773 100755
--- a/versioned_docs/version-8.x/headers.md
+++ b/versioned_docs/version-8.x/headers.md
@@ -13,14 +13,14 @@ We've seen how to configure the header title already, but let's go over that aga
Each screen has `options` which is either an object or a function that returns an object, that contains various configuration options. The one we use for the header title is `title`, as shown in the following example.
-
-
-
-```js name="Setting header title" snack
+```js name="Setting header title" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
function HomeScreen() {
return (
@@ -33,14 +33,14 @@ function HomeScreen() {
// codeblock-focus-start
const MyStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
// highlight-start
options: {
title: 'My home',
},
// highlight-end
- },
+ }),
},
});
// codeblock-focus-end
@@ -52,65 +52,13 @@ export default function App() {
}
```
-
-
-
-```js name="Setting header title" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function MyStack() {
- return (
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-

## Using params in the title
In order to use params in the title, we need to make `options` for the screen a function that returns a configuration object. If we make `options` a function then React Navigation will call it with an object containing `{ navigation, route }` - in this case, all we care about is `route`, which is the same object that is passed to your screen props as `route` prop. You may recall that we can get the params through `route.params`, and so we do this below to extract a param and use it as a title.
-
-
-
-```js name="Using params in the title" snack
+```js name="Using params in the title" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -121,7 +69,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -149,20 +97,20 @@ function ProfileScreen() {
// codeblock-focus-start
const MyStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
title: 'My home',
},
- },
- Profile: {
+ }),
+ Profile: createNativeStackScreen({
screen: ProfileScreen,
// highlight-start
options: ({ route }) => ({
title: route.params.name,
}),
// highlight-end
- },
+ }),
},
});
// codeblock-focus-end
@@ -174,79 +122,6 @@ export default function App() {
}
```
-
-
-
-```js name="Using params in the title" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- return (
-
-
- navigation.navigate('Profile', {
- name: 'Jane',
- })
- }
- >
- Go to Profile
-
-
- );
-}
-
-function ProfileScreen() {
- return (
-
- Profile Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function MyStack() {
- return (
-
-
- ({
- title: route.params.name,
- })}
- // highlight-end
- />
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
The argument that is passed in to the `options` function is an object with the following properties:
- `navigation` - The [navigation object](navigation-object.md) for the screen.
@@ -258,7 +133,7 @@ We only needed the `route` object in the above example but you may in some cases
It's often necessary to update the `options` configuration for the active screen from the mounted screen component itself. We can do this using `navigation.setOptions`
-```js name="Updating options" snack
+```js name="Updating options" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -269,7 +144,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -314,10 +189,7 @@ There are three key properties to use when customizing the style of your header:
- `headerTintColor`: the back button and title both use this property as their color. In the example below, we set the tint color to white (`#fff`) so the back button and the header title would be white.
- `headerTitleStyle`: if we want to customize the `fontFamily`, `fontWeight` and other `Text` style properties for the title, we can use this to do it.
-
-
-
-```js name="Header styles" snack
+```js name="Header styles" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
@@ -334,7 +206,7 @@ function HomeScreen() {
// codeblock-focus-start
const MyStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
title: 'My home',
@@ -348,7 +220,7 @@ const MyStack = createNativeStackNavigator({
},
// highlight-end
},
- },
+ }),
},
});
// codeblock-focus-end
@@ -360,62 +232,6 @@ export default function App() {
}
```
-
-
-
-```js name="Header styles" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function MyStack() {
- return (
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-

There are a couple of things to notice here:
@@ -427,10 +243,7 @@ There are a couple of things to notice here:
It is common to want to configure the header in a similar way across many screens. For example, your company brand color might be red and so you want the header background color to be red and the tint color to be white. Conveniently, these are the colors we're using in our running example, and you'll notice that when you navigate to the `DetailsScreen` the colors go back to the defaults. Wouldn't it be awful if we had to copy the `options` header style properties from `Home` to `Details`, and for every single screen we use in our app? Thankfully, we do not. We can instead move the configuration up to the native stack navigator under `screenOptions`:
-
-
-
-```js name="Common screen options" snack
+```js name="Common screen options" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -441,7 +254,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -475,12 +288,12 @@ const MyStack = createNativeStackNavigator({
},
// highlight-end
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
- },
- Details: {
+ }),
+ Details: createNativeStackScreen({
screen: DetailsScreen,
- },
+ }),
},
});
// codeblock-focus-end
@@ -492,88 +305,13 @@ export default function App() {
}
```
-
-
-
-```js name="Common screen options" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- return (
-
- Home Screen
- navigation.navigate('Details')}>
- Go to Details
-
-
- );
-}
-
-function DetailsScreen() {
- return (
-
- Details Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function MyStack() {
- return (
-
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
Now, any screen that belongs to this navigator will have our wonderful branded styles. Surely though, there must be a way to override these options if we need to?
## Replacing the title with a custom component
Sometimes you need more control than just changing the text and styles of your title -- for example, you may want to render an image in place of the title, or make the title into a button. In these cases you can completely override the component used for the title and provide your own.
-
-
-
-```js name="Custom title" snack
+```js name="Custom title" snack static2dynamic
import * as React from 'react';
import { Text, View, Image } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
@@ -617,66 +355,8 @@ export default function App() {
}
```
-
-
-
-```js name="Custom title" snack
-import * as React from 'react';
-import { Text, View, Image } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function LogoTitle() {
- return (
-
- );
-}
-
-function MyStack() {
- return (
-
- ,
- }}
- />
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-

-You might be wondering, why `headerTitle` when we provide a component and not `title`, like before? The reason is that `headerTitle` is a property that is specific to stack navigators, the `headerTitle` defaults to a `Text` component that displays the `title`.
-
-
-
:::note
You might be wondering, why `headerTitle` when we provide a component and not `title`, like before? The reason is that `headerTitle` is a property that is specific to headers, whereas `title` will be used for tab bars, drawers etc. as well. The `headerTitle` defaults to a `Text` component that displays the `title`.
diff --git a/versioned_docs/version-8.x/hello-react-navigation.md b/versioned_docs/version-8.x/hello-react-navigation.md
index 74e4e98f602..b2598fb2267 100755
--- a/versioned_docs/version-8.x/hello-react-navigation.md
+++ b/versioned_docs/version-8.x/hello-react-navigation.md
@@ -29,7 +29,7 @@ npm install @react-navigation/native-stack
## Installing the elements library
-The [`@react-navigation/elements`](elements.md) library provides a set of components that are designed to work well with React Navigation. We'll use a few of these components in this guide. So let's install it first:
+The [`@react-navigation/elements`](elements.md) library provides a set of components that are designed to work well with React Navigation. We'll use a few of these components such as `Button` in this guide. So let's install it first:
```bash npm2yarn
npm install @react-navigation/elements
@@ -40,17 +40,22 @@ npm install @react-navigation/elements
-`createNativeStackNavigator` is a function that takes a configuration object containing the screens and customization options. The screens are React Components that render the content displayed by the navigator.
+`createNativeStackNavigator` is a function that takes a configuration object for the navigator including the list of screens to include.
+
+`createNativeStackScreen` is a function that takes a configuration object for a screen, where the `screen` property is the component to render for that screen. A screen is a React Component that renders the content displayed by the navigator, or a nested navigator which we'll learn about later.
`createStaticNavigation` is a function that takes the navigator defined earlier and returns a component that can be rendered in the app. It's only called once in the app. Usually, we'd render the returned component at the root of our app, which is usually the component exported from `App.js`, `App.tsx` etc., or used with `AppRegistry.registerComponent`, `Expo.registerRootComponent` etc.
-```js name="Native Stack Example" snack
-// In App.js in a new project
+To create a basic native stack navigator with a single screen, we can add the following code in the entry file of our app (e.g., `App.tsx`, `index.tsx` etc.):
+```js name="Native Stack Example" snack
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
function HomeScreen() {
return (
@@ -62,7 +67,9 @@ function HomeScreen() {
const RootStack = createNativeStackNavigator({
screens: {
- Home: HomeScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
},
});
@@ -86,9 +93,9 @@ In a typical React Native app, the `createStaticNavigation` function should be o
`NavigationContainer` is a component that manages our navigation tree and contains the [navigation state](navigation-state.md). This component must wrap all the navigators in the app. Usually, we'd render this component at the root of our app, which is usually the component exported from `App.js`, `App.tsx` etc., or used with `AppRegistry.registerComponent`, `Expo.registerRootComponent` etc.
-```js name="Native Stack Example" snack
-// In App.js in a new project
+To create a basic native stack navigator with a single screen, we can add the following code in the entry file of our app (e.g., `App.tsx`, `index.tsx` etc.):
+```js name="Native Stack Example" snack
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
@@ -146,14 +153,14 @@ All of the route configuration is specified as props to our navigator. We haven'
Let's add a second screen to our native stack navigator and configure the `Home` screen to render first:
-
-
-
-```js name="Native Stack Example" snack
+```js name="Native Stack Example" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
function HomeScreen() {
return (
@@ -176,8 +183,12 @@ const RootStack = createNativeStackNavigator({
// highlight-next-line
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
// codeblock-focus-end
@@ -191,98 +202,22 @@ export default function App() {
Now our stack has two _routes_, a `Home` route and a `Details` route. A route can be specified by under the `screens` property. The name of the property under `screens` corresponds to the name of the route we will use to navigate, and the value corresponds to the component it'll render.
-
-
-
-```js name="Native Stack Example" snack
-import * as React from 'react';
-import { View, Text } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-function DetailsScreen() {
- return (
-
- Details Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function RootStack() {
- return (
- // highlight-next-line
-
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-Now our stack has two _routes_, a `Home` route and a `Details` route. A route can be specified by using the `Screen` component. The `Screen` component accepts a `name` prop which corresponds to the name of the route we will use to navigate, and a `component` prop which corresponds to the component it'll render.
-
-:::warning
-
-When using the dynamic API, the `component` prop accepts a component, not a render function. Don't pass an inline function (e.g. `component={() => }`), or your component will unmount and remount losing all state when the parent component re-renders. See [Passing additional props](#passing-additional-props) for alternatives.
-
-:::
-
-
-
-
Here, the `Home` route corresponds to the `HomeScreen` component, and the `Details` route corresponds to the `DetailsScreen` component. The initial route for the stack is the `Home` route. Try changing it to `Details` and reload the app (React Native's Fast Refresh won't update changes from `initialRouteName`, as you might expect), notice that you will now see the `Details` screen. Then change it back to `Home` and reload once more.
## Specifying options
Each screen in the navigator can specify some options for the navigator, such as the title to render in the header.
-
-
+To specify the options, we'll add an `options` property to the screen configuration:
-To specify the options, we'll change how we have specified the screen component. Instead of specifying the screen component as the value, we can also specify an object with a `screen` property:
-
-```js
-const RootStack = createNativeStackNavigator({
- initialRouteName: 'Home',
- screens: {
- Home: {
- // highlight-next-line
- screen: HomeScreen,
- },
- Details: DetailsScreen,
- },
-});
-```
-
-This will let us specify additional options for the screen.
-
-Now, we can add an `options` property:
-
-```js name="Options for Screen" snack
+```js name="Options for Screen" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
function HomeScreen() {
return (
@@ -304,15 +239,17 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
// highlight-start
options: {
title: 'Overview',
},
// highlight-end
- },
- Details: DetailsScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
// codeblock-focus-end
@@ -326,11 +263,14 @@ export default function App() {
Sometimes we will want to specify the same options for all of the screens in the navigator. For that, we can add a `screenOptions` property to the configuration:
-```js name="Common options for Screens" snack
+```js name="Common options for Screens" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
function HomeScreen() {
return (
@@ -357,13 +297,15 @@ const RootStack = createNativeStackNavigator({
},
// highlight-end
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
title: 'Overview',
},
- },
- Details: DetailsScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
// codeblock-focus-end
@@ -375,120 +317,6 @@ export default function App() {
}
```
-
-
-
-Any customization options can be passed in the `options` prop for each screen component:
-
-```js name="Options for Screen" snack
-import * as React from 'react';
-import { View, Text } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-function DetailsScreen() {
- return (
-
- Details Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-function RootStack() {
- return (
- // codeblock-focus-start
-
-
-
-
- // codeblock-focus-end
- );
-}
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-Sometimes we will want to specify the same options for all of the screens in the navigator. For that, we can pass a `screenOptions` prop to the navigator:
-
-```js name="Common options for Screens" snack
-import * as React from 'react';
-import { View, Text } from 'react-native';
-import { NavigationContainer } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-function HomeScreen() {
- return (
-
- Home Screen
-
- );
-}
-
-function DetailsScreen() {
- return (
-
- Details Screen
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-function RootStack() {
- return (
- // codeblock-focus-start
-
-
-
-
- // codeblock-focus-end
- );
-}
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
## Passing additional props
diff --git a/versioned_docs/version-8.x/migration-guides.md b/versioned_docs/version-8.x/migration-guides.md
index 2ba276c440a..86ac82af8c8 100644
--- a/versioned_docs/version-8.x/migration-guides.md
+++ b/versioned_docs/version-8.x/migration-guides.md
@@ -6,6 +6,7 @@ sidebar_label: Migration Guides
This page contains links to pages that will guide you through the process of upgrading React Navigation:
+- [Upgrading from 7.x to 8.x](../version-8.x/upgrading-from-7.x.md)
- [Upgrading from 6.x to 7.x](../version-7.x/upgrading-from-6.x.md)
- [Upgrading from 5.x to 6.x](../version-6.x/upgrading-from-5.x.md)
- [Upgrading from 4.x to 5.x](../version-5.x/upgrading-from-4.x.md)
diff --git a/versioned_docs/version-8.x/multiple-drawers.md b/versioned_docs/version-8.x/multiple-drawers.md
index 8b369a690a7..604a9ad71df 100644
--- a/versioned_docs/version-8.x/multiple-drawers.md
+++ b/versioned_docs/version-8.x/multiple-drawers.md
@@ -288,10 +288,7 @@ An alternative approach is to nest 2 [drawer navigators](drawer-navigator.md) in
Here we have 2 drawer navigators nested inside each other, one is positioned on left and the other on the right:
-
-
-
-```js name="Multiple drawers" snack
+```js name="Multiple drawers" snack static2dynamic
import * as React from 'react';
import { View } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
@@ -337,60 +334,6 @@ export default function App() {
}
```
-
-
-
-```js name="Multiple drawers" snack
-import * as React from 'react';
-import { View } from 'react-native';
-import { createDrawerNavigator } from '@react-navigation/drawer';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { Button } from '@react-navigation/elements';
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- return (
-
- navigation.openDrawer()}>Open drawer
-
- );
-}
-
-const LeftDrawer = createDrawerNavigator();
-
-const LeftDrawerScreen = () => {
- return (
-
-
-
- );
-};
-
-const RightDrawer = createDrawerNavigator();
-
-const RightDrawerScreen = () => {
- return (
-
-
-
- );
-};
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
@@ -404,16 +347,18 @@ To solve this, we need to use [`navigation.getParent`](navigation-object.md#getp
navigation.getParent().openDrawer()}>Open right drawer
```
-However, this means that our button needs to know about the parent navigators, which isn't ideal. If our button is further nested inside other navigators, it'd need multiple `getParent()` calls. To address this, we can use the [`id` prop](navigator.md#id) to identify the parent navigator.
+However, this means that our button needs to know about the parent navigators, which isn't ideal. If our button is further nested inside other navigators, it'd need multiple `getParent()` calls. To solve this, we can pass the name of the screen where the navigator is to the `getParent` method to directly refer to the desired navigator.
+
+In this case:
+
+- `navigation.getParent('Home').openDrawer()` opens the left drawer since `'Home'` is a screen in the left drawer navigator.
+- `navigation.getParent('HomeDrawer').openDrawer()` opens the right drawer since `'HomeDrawer'` is a screen in the right drawer navigator.
To customize the contents of the drawer, we can use the [`drawerContent` prop](drawer-navigator.md#drawercontent) to pass in a function that renders a custom component.
The final code would look like this:
-
-
-
-```js name="Multiple drawers navigators" snack
+```js name="Multiple drawers navigators" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
@@ -428,10 +373,10 @@ function HomeScreen() {
return (
- navigation.getParent('LeftDrawer').openDrawer()}>
+ navigation.getParent('Home').openDrawer()}>
Open left drawer
- navigation.getParent('RightDrawer').openDrawer()}>
+ navigation.getParent('HomeDrawer').openDrawer()}>
Open right drawer
@@ -446,8 +391,7 @@ function RightDrawerContent() {
);
}
-const LeftDrawerScreen = createDrawerNavigator({
- id: 'LeftDrawer',
+const LeftDrawer = createDrawerNavigator({
screenOptions: {
drawerPosition: 'left',
},
@@ -456,105 +400,27 @@ const LeftDrawerScreen = createDrawerNavigator({
},
});
-const RightDrawerScreen = createDrawerNavigator({
- id: 'RightDrawer',
+const RightDrawer = createDrawerNavigator({
drawerContent: (props) => ,
screenOptions: {
drawerPosition: 'right',
headerShown: false,
},
screens: {
- HomeDrawer: LeftDrawerScreen,
+ HomeDrawer: LeftDrawer,
},
});
-const Navigation = createStaticNavigation(RightDrawerScreen);
+const Navigation = createStaticNavigation(RightDrawer);
export default function App() {
return ;
}
```
-
-
-
-```js name="Multiple drawers navigators" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { createDrawerNavigator } from '@react-navigation/drawer';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { Button } from '@react-navigation/elements';
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- return (
-
- navigation.getParent('LeftDrawer').openDrawer()}>
- Open left drawer
-
- navigation.getParent('RightDrawer').openDrawer()}>
- Open right drawer
-
-
- );
-}
-
-function RightDrawerContent() {
- return (
-
- This is the right drawer
-
- );
-}
-
-const LeftDrawer = createDrawerNavigator();
-
-function LeftDrawerScreen() {
- return (
-
-
-
- );
-}
-
-const RightDrawer = createDrawerNavigator();
-
-function RightDrawerScreen() {
- return (
- }
- screenOptions={{
- drawerPosition: 'right',
- headerShown: false,
- }}
- >
-
-
- );
-}
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
-Here, we are passing `"LeftDrawer"` and `"RightDrawer"` strings (you can use any string here) in the `id` prop of the drawer navigators. Then we use `navigation.getParent('LeftDrawer').openDrawer()` to open the left drawer and `navigation.getParent('RightDrawer').openDrawer()` to open the right drawer.
-
## Summary
- To have multiple drawers, you can use [`react-native-drawer-layout`](drawer-layout.md) directly in combination with a drawer navigator.
- The [`drawerPosition`](drawer-layout.md#drawerposition) prop can be used to position the drawer on the right.
- The methods to control the drawer can be passed down using context API when using [`react-native-drawer-layout`](drawer-layout.md).
-- When nesting multiple navigators, you can use [`navigation.getParent`](navigation-object.md#getparent) in combination with the [`id` prop](navigator.md#id) to refer to the desired drawer.
+- When nesting multiple navigators, you can use [`navigation.getParent`](navigation-object.md#getparent) with a screen name to refer to the desired drawer.
diff --git a/versioned_docs/version-8.x/native-bottom-tab-navigator.md b/versioned_docs/version-8.x/native-bottom-tab-navigator.md
deleted file mode 100755
index 9fddb223207..00000000000
--- a/versioned_docs/version-8.x/native-bottom-tab-navigator.md
+++ /dev/null
@@ -1,445 +0,0 @@
----
-id: native-bottom-tab-navigator
-title: Native Bottom Tabs Navigator
-sidebar_label: Native Bottom Tabs
----
-
-:::warning
-
-This navigator is currently experimental. The API will change in future releases.
-
-Currently only iOS and Android are supported. Use [`createBottomTabNavigator`](bottom-tab-navigator.md) for web support.
-
-:::
-
-Native Bottom Tabs displays screens with a tab bar to switch between them.
-
-
-
-
-
-
-
-
-
-The navigator uses native components on iOS and Android for better platform integration. On iOS, it uses `UITabBarController` and on Android, it uses `BottomNavigationView`.
-
-## Installation
-
-To use this navigator, ensure that you have [`@react-navigation/native` and its dependencies (follow this guide)](getting-started.md), then install [`@react-navigation/bottom-tabs`](https://github.com/react-navigation/react-navigation/tree/main/packages/bottom-tabs):
-
-```bash npm2yarn
-npm install @react-navigation/bottom-tabs
-```
-
-The navigator requires React Native 0.79 or above is required. If you're using [Expo](https://expo.dev/), it requires SDK 53 or above.
-
-## Usage
-
-To use this navigator, import it from `@react-navigation/bottom-tabs/unstable`:
-
-```js name="Bottom Tab Navigator" static2dynamic
-import { createNativeBottomTabNavigator } from '@react-navigation/bottom-tabs/unstable';
-
-const MyTabs = createNativeBottomTabNavigator({
- screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
- },
-});
-```
-
-## Notes
-
-- Liquid Glass effect on iOS 26+ requires your app to be built with Xcode 26 or above.
-- On Android, at most 5 tabs are supported. This is a limitation of the underlying native component.
-
-## API Definition
-
-### Props
-
-In addition to the [common props](navigator.md#configuration) shared by all navigators, the bottom tab navigator accepts the following additional props:
-
-#### `backBehavior`
-
-This controls what happens when `goBack` is called in the navigator. This includes pressing the device's back button or back gesture on Android.
-
-It supports the following values:
-
-- `firstRoute` - return to the first screen defined in the navigator (default)
-- `initialRoute` - return to initial screen passed in `initialRouteName` prop, if not passed, defaults to the first screen
-- `order` - return to screen defined before the focused screen
-- `history` - return to last visited screen in the navigator; if the same screen is visited multiple times, the older entries are dropped from the history
-- `fullHistory` - return to last visited screen in the navigator; doesn't drop duplicate entries unlike `history` - this behavior is useful to match how web pages work
-- `none` - do not handle back button
-
-### Options
-
-The following [options](screen-options.md) can be used to configure the screens in the navigator. These can be specified under `screenOptions` prop of `Tab.Navigator` or `options` prop of `Tab.Screen`.
-
-#### `title`
-
-Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
-
-#### `tabBarSystemItem`
-
-Uses iOS built-in tab bar items with standard iOS styling and localized titles. Supported values:
-
-- `bookmarks`
-- `contacts`
-- `downloads`
-- `favorites`
-- `featured`
-- `history`
-- `more`
-- `mostRecent`
-- `mostViewed`
-- `recents`
-- `search`
-- `topRated`
-
-The [`tabBarIcon`](#tabbaricon) and [`tabBarLabel`](#tabbarlabel) options will override the icon and label from the system item. If you want to keep the system behavior on iOS, but need to provide icon and label for other platforms, use `Platform.OS` or `Platform.select` to conditionally set `undefined` for `tabBarIcon` and `tabBarLabel` on iOS.
-
-##### Search tab on iOS 26+
-
-The `tabBarSystemItem` option has special styling and behavior when set to `search` on iOS 26+.
-
-Additionally, when the `search` tab is selected, the tab bar transforms into a search field if the screen in the tab navigator or a nested [native stack navigator](native-stack-navigator.md) has [`headerSearchBarOptions`](native-stack-navigator.md#headersearchbaroptions) configured and the native header is shown with [`headerShown: true`](native-stack-navigator.md#headershown). This won't work if a custom header is provided with the `header` option.
-
-Example:
-
-```js
-tabBarSystemItem: 'search',
-headerShown: true,
-headerSearchBarOptions: {
- placeholder: 'Search',
-},
-```
-
-
-
-
-
-#### `tabBarLabel`
-
-Title string of a tab displayed in the tab bar.
-
-Overrides the label provided by [`tabBarSystemItem`](#tabbarsystemitem) on iOS.
-
-If not provided, or set to `undefined`:
-
-- The system values are used if [`tabBarSystemItem`](#tabbarsystemitem) is set on iOS.
-- Otherwise, it falls back to the [`title`](#title) or route name.
-
-#### `tabBarLabelVisibilityMode`
-
-The label visibility mode for the tab bar items. Supported values:
-
-- `auto` - the system decides when to show or hide labels
-- `selected` - labels are shown only for the selected tab
-- `labeled` - labels are always shown
-- `unlabeled` - labels are never shown
-
-Only supported on Android.
-
-#### `tabBarLabelStyle`
-
-Style object for the tab label. Supported properties:
-
-- `fontFamily`
-- `fontSize`
-- `fontWeight`
-- `fontStyle`
-
-Example:
-
-```js
-tabBarLabelStyle: {
- fontSize: 16,
- fontFamily: 'Georgia',
- fontWeight: 300,
-},
-```
-
-#### `tabBarIcon`
-
-Icon to display for the tab. It overrides the icon provided by [`tabBarSystemItem`](#tabbarsystemitem) on iOS.
-
-It can be an icon object or a function that given `{ focused: boolean, color: string, size: number }` returns an icon object.
-
-The icon can be of following types:
-
-- Local image - Supported on iOS and Android
-
- ```js
- tabBarIcon: {
- type: 'image',
- source: require('./path/to/icon.png'),
- }
- ```
-
- On iOS, you can additionally pass a `tinted` property to control whether the icon should be tinted with the active/inactive color:
-
- ```js
- tabBarIcon: {
- type: 'image',
- source: require('./path/to/icon.png'),
- tinted: false,
- }
- ```
-
- The image is tinted by default.
-
-- [SF Symbols](https://developer.apple.com/sf-symbols/) name - Supported on iOS
-
- ```js
- tabBarIcon: {
- type: 'sfSymbol',
- name: 'heart',
- }
- ```
-
-- [Drawable resource](https://developer.android.com/guide/topics/resources/drawable-resource) name - Supported on Android
-
- ```js
- tabBarIcon: {
- type: 'drawableResource',
- name: 'sunny',
- }
- ```
-
-To render different icons for active and inactive states, you can use a function:
-
-```js
-tabBarIcon: ({ focused }) => {
- return {
- type: 'sfSymbol',
- name: focused ? 'heart' : 'heart-outline',
- };
-},
-```
-
-This is only supported on iOS. On Android, the icon specified for inactive state will be used for both active and inactive states.
-
-To provide different icons for different platforms, you can use [`Platform.select`](https://reactnative.dev/docs/platform-specific-code):
-
-```js
-tabBarIcon: Platform.select({
- ios: {
- type: 'sfSymbol',
- name: 'heart',
- },
- android: {
- type: 'drawableResource',
- name: 'heart_icon',
- },
-});
-```
-
-#### `tabBarBadge`
-
-Text to show in a badge on the tab icon. Accepts a `string` or a `number`.
-
-#### `tabBarBadgeStyle`
-
-Style for the badge on the tab icon. Supported properties:
-
-- `backgroundColor`
-- `color`
-
-Example:
-
-```js
-tabBarBadgeStyle: {
- backgroundColor: 'yellow',
- color: 'black',
-},
-```
-
-Only supported on Android.
-
-#### `tabBarActiveTintColor`
-
-Color for the icon and label in the active tab.
-
-#### `tabBarInactiveTintColor`
-
-Color for the icon and label in the inactive tabs.
-
-Only supported on Android.
-
-#### `tabBarActiveIndicatorColor`
-
-Background color of the active indicator.
-
-Only supported on Android.
-
-#### `tabBarActiveIndicatorEnabled`
-
-Whether the active indicator should be used. Defaults to `true`.
-
-Only supported on Android.
-
-#### `tabBarRippleColor`
-
-Color of the ripple effect when pressing a tab.
-
-Only supported on Android.
-
-#### `tabBarStyle`
-
-Style object for the tab bar. Supported properties:
-
-- `backgroundColor` - Only supported on Android and iOS 18 and below.
-- `shadowColor` - Only supported on iOS 18 and below.
-
-On iOS 26+, the background color automatically changes based on the content behind the tab bar and can't be overridden.
-
-#### `tabBarBlurEffect`
-
-Blur effect applied to the tab bar on iOS 18 and lower when tab screen is selected.
-
-Supported values:
-
-- `none` - no blur effect
-- `systemDefault` - default blur effect applied by the system
-- `extraLight`
-- `light`
-- `dark`
-- `regular`
-- `prominent`
-- `systemUltraThinMaterial`
-- `systemThinMaterial`
-- `systemMaterial`
-- `systemThickMaterial`
-- `systemChromeMaterial`
-- `systemUltraThinMaterialLight`
-- `systemThinMaterialLight`
-- `systemMaterialLight`
-- `systemThickMaterialLight`
-- `systemChromeMaterialLight`
-- `systemUltraThinMaterialDark`
-- `systemThinMaterialDark`
-- `systemMaterialDark`
-- `systemThickMaterialDark`
-- `systemChromeMaterialDark`
-
-Defaults to `systemDefault`.
-
-Only supported on iOS 18 and below.
-
-#### `tabBarControllerMode`
-
-The display mode for the tab bar. Supported values:
-
-- `auto` - the system sets the display mode based on the tab’s content
-- `tabBar` - the system displays the content only as a tab bar
-- `tabSidebar` - the tab bar is displayed as a sidebar
-
-Only supported on iOS 18 and above. Not supported on tvOS.
-
-#### `tabBarMinimizeBehavior`
-
-The minimize behavior for the tab bar. Supported values:
-
-- `auto` - resolves to the system default minimize behavior
-- `never` - the tab bar does not minimize
-- `onScrollDown` - the tab bar minimizes when scrolling down and
- expands when scrolling back up
-- `onScrollUp` - the tab bar minimizes when scrolling up and expands
- when scrolling back down
-
-Only supported on iOS 26 and above.
-
-
-
-
-
-#### `lazy`
-
-Whether this screen should render only after the first time it's accessed. Defaults to `true`. Set it to `false` if you want to render the screen on the initial render of the navigator.
-
-#### `popToTopOnBlur`
-
-Boolean indicating whether any nested stack should be popped to the top of the stack when navigating away from this tab. Defaults to `false`.
-
-It only works when there is a stack navigator (e.g. [stack navigator](stack-navigator.md) or [native stack navigator](native-stack-navigator.md)) nested under the tab navigator.
-
-### Header related options
-
-The navigator does not show a header by default. It renders a native stack header if `headerShown` is set to `true` in the screen options explicitly, or if a custom header is provided with the `header` option. Header related options require a header to be shown.
-
-It supports most of the [header related options supported in `@react-navigation/native-stack`](native-stack-navigator.md#header-related-options) apart from the options related to the back button (prefixed with `headerBack`).
-
-### Events
-
-The navigator can [emit events](navigation-events.md) on certain actions. Supported events are:
-
-#### `tabPress`
-
-This event is fired when the user presses the tab button for the current screen in the tab bar. By default a tab press does several things:
-
-- If the tab is not focused, tab press will focus that tab
-- If the tab is already focused:
- - If the screen for the tab renders a scroll view, you can use [`useScrollToTop`](use-scroll-to-top.md) to scroll it to top
- - If the screen for the tab renders a stack navigator, a `popToTop` action is performed on the stack
-
-The default behavior of the tab press is controlled natively and cannot be prevented.
-
-```js
-React.useEffect(() => {
- const unsubscribe = navigation.addListener('tabPress', (e) => {
- // Do something manually
- // ...
- });
-
- return unsubscribe;
-}, [navigation]);
-```
-
-#### `transitionStart`
-
-This event is fired when the transition animation starts for the current screen.
-
-Example:
-
-```js
-React.useEffect(() => {
- const unsubscribe = navigation.addListener('transitionStart', (e) => {
- // Do something
- });
-
- return unsubscribe;
-}, [navigation]);
-```
-
-#### `transitionEnd`
-
-This event is fired when the transition animation ends for the current screen.
-
-Example:
-
-```js
-React.useEffect(() => {
- const unsubscribe = navigation.addListener('transitionEnd', (e) => {
- // Do something
- });
-
- return unsubscribe;
-}, [navigation]);
-```
-
-### Helpers
-
-The tab navigator adds the following methods to the navigation object:
-
-#### `jumpTo`
-
-Navigates to an existing screen in the tab navigator. The method accepts following arguments:
-
-- `name` - _string_ - Name of the route to jump to.
-- `params` - _object_ - Screen params to use for the destination route.
-
-```js
-navigation.jumpTo('Profile', { owner: 'Michaś' });
-```
diff --git a/versioned_docs/version-8.x/native-stack-navigator.md b/versioned_docs/version-8.x/native-stack-navigator.md
index 9d673794803..799d90666a1 100755
--- a/versioned_docs/version-8.x/native-stack-navigator.md
+++ b/versioned_docs/version-8.x/native-stack-navigator.md
@@ -602,9 +602,12 @@ Only supported on iOS.
#### `animationDuration`
-Changes the duration (in milliseconds) of `slide_from_bottom`, `fade_from_bottom`, `fade` and `simple_push` transitions on iOS. Defaults to `350`.
+Changes the duration (in milliseconds) of `slide_from_bottom`, `fade_from_bottom`, `fade` and `simple_push` transitions on iOS. Defaults to `500`.
-The duration of `default` and `flip` transitions isn't customizable.
+The duration is not customizable for:
+
+- Screens with `default` and `flip` animations
+- Screens with `presentation` set to `modal`, `formSheet`, `pageSheet` (regardless of animation)
Only supported on iOS.
@@ -1249,9 +1252,9 @@ A callback that gets called when search bar has lost focus.
A callback that gets called when the cancel button is pressed.
-##### `onChangeText`
+##### `onChange`
-A callback that gets called when the text changes. It receives the current text value of the search bar.
+A callback that gets called when the text changes. It receives en event containing the current text value of the search bar.
Example:
@@ -1261,7 +1264,7 @@ const [search, setSearch] = React.useState('');
React.useLayoutEffect(() => {
navigation.setOptions({
headerSearchBarOptions: {
- onChangeText: (event) => setSearch(event.nativeEvent.text),
+ onChange: (event) => setSearch(event.nativeEvent.text),
},
});
}, [navigation]);
@@ -1352,6 +1355,48 @@ React.useEffect(() => {
}, [navigation]);
```
+#### `gestureCancel`
+
+This event is fired when a swipe back gesture is canceled on iOS.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('gestureCancel', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+Only supported on iOS.
+
+#### `sheetDetentChange`
+
+This event is fired when a screen with `presentation: 'formSheet'` changes its detent.
+
+Event data:
+
+- `e.data.index` - The current detent index in the `sheetAllowedDetents` array.
+- `e.data.stable` - On Android, `false` means the user is dragging the sheet or it is settling. On iOS, this is always `true`.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('sheetDetentChange', (e) => {
+ console.log('Detent index:', e.data.index);
+ console.log('Is stable:', e.data.stable);
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+Only supported on Android and iOS.
+
### Helpers
The native stack navigator adds the following methods to the navigation object:
diff --git a/versioned_docs/version-8.x/navigating.md b/versioned_docs/version-8.x/navigating.md
index 73057ef5193..4f2ad4031a5 100755
--- a/versioned_docs/version-8.x/navigating.md
+++ b/versioned_docs/version-8.x/navigating.md
@@ -4,6 +4,9 @@ title: Moving between screens
sidebar_label: Moving between screens
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
In the previous section, we defined a stack navigator with two routes (`Home` and `Details`), but we didn't learn how to let a user navigate from `Home` to `Details` (although we did learn how to change the _initial_ route in our code, but forcing our users to clone our repository and change the route in our code in order to see another screen is arguably among the worst user experiences one could imagine).
If this was a web browser, we'd be able to write something like this:
@@ -28,7 +31,7 @@ We'll do something similar to the latter, but rather than using a `window.locati
## Navigating to a new screen
-```js name="Navigating to a new screen" snack
+```js name="Navigating to a new screen" snack static2dynamic
// codeblock-focus-start
import * as React from 'react';
import { View, Text } from 'react-native';
@@ -36,12 +39,15 @@ import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
// highlight-next-line
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -69,8 +75,12 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -87,7 +97,7 @@ export default function App() {
Let's break this down:
-- `navigation` - the `navigation` object is returned from the [`useNavigation`](use-navigation.md) hook (more about this later in ["The navigation object in depth"](navigation-object.md)).
+- `navigation` - the [`navigation`](navigation-object.md) object is returned from the [`useNavigation`](use-navigation.md) hook - it takes the name of the current route as an argument (in this case, `Home`).
- `navigate('Details')` - we call the `navigate` function (on the `navigation` object — naming is hard!) with the name of the route that we'd like to move the user to.
:::note
@@ -100,18 +110,21 @@ So we now have a stack with two routes: 1) the `Home` route 2) the `Details` rou
## Navigate to a screen multiple times
-```js name="Navigate to a screen multiple times" snack
+```js name="Navigate to a screen multiple times" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -125,7 +138,7 @@ function HomeScreen() {
// codeblock-focus-start
function DetailsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
return (
@@ -143,8 +156,12 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -159,18 +176,21 @@ If you run this code, you'll notice that when you tap "Go to Details... again",
Let's suppose that we actually _want_ to add another details screen. This is pretty common in cases where you pass in some unique data to each route (more on that later when we talk about `params`!). To do this, we can change `navigate` to `push`. This allows us to express the intent to add another route regardless of the existing navigation history.
-```js name="Navigate to a screen multiple times" snack
+```js name="Navigate to a screen multiple times" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -183,7 +203,7 @@ function HomeScreen() {
}
function DetailsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
return (
@@ -200,8 +220,12 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -224,18 +248,21 @@ The header provided by the native stack navigator will automatically include a b
Sometimes you'll want to be able to programmatically trigger this behavior, and for that, you can use `navigation.goBack()`.
-```js name="Going back" snack
+```js name="Going back" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -249,7 +276,7 @@ function HomeScreen() {
// codeblock-focus-start
function DetailsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
return (
@@ -268,8 +295,12 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -292,18 +323,21 @@ On Android, React Navigation hooks in to the hardware back button and fires the
Another common requirement is to be able to go back _multiple_ screens -- for example, if you are several screens deep in a stack and want to dismiss all of them to go back to the first screen. In this case, we know that we want to go back to `Home` so we can use `popTo('Home')`. Another alternative would be `navigation.popToTop()`, which goes back to the first screen in the stack.
-```js name="Going back to specific screen" snack
+```js name="Going back to specific screen" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -317,7 +351,7 @@ function HomeScreen() {
// codeblock-focus-start
function DetailsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
return (
@@ -340,8 +374,12 @@ function DetailsScreen() {
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
diff --git a/versioned_docs/version-8.x/navigation-actions.md b/versioned_docs/version-8.x/navigation-actions.md
index a4480e69e77..32b41af317c 100755
--- a/versioned_docs/version-8.x/navigation-actions.md
+++ b/versioned_docs/version-8.x/navigation-actions.md
@@ -889,3 +889,116 @@ export default function App() {
```
If the `source` property is explicitly set to `undefined`, it'll replace the params for the focused route.
+
+### pushParams
+
+The `pushParams` action allows to add a new entry to the history stack with new params. It takes the following arguments:
+
+- `params` - _object_ - required - New params to use for the route.
+
+```js name="Common actions pushParams" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ CommonActions,
+} from '@react-navigation/native';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+
+function ProductListScreen({ route }) {
+ const navigation = useNavigation();
+ const filter = route.params?.filter || 'all';
+
+ return (
+
+ Product List
+ Filter: {filter}
+ {
+ // codeblock-focus-start
+ navigation.dispatch(CommonActions.pushParams({ filter: 'popular' }));
+ // codeblock-focus-end
+ }}
+ >
+ Show popular
+
+ {
+ // codeblock-focus-start
+ navigation.dispatch(CommonActions.pushParams({ filter: 'new' }));
+ // codeblock-focus-end
+ }}
+ >
+ Show new
+
+ {
+ navigation.dispatch(CommonActions.goBack());
+ }}
+ >
+ Go back
+
+
+ );
+}
+
+function SettingsScreen() {
+ return (
+
+ Settings
+
+ );
+}
+
+const HomeTabs = createBottomTabNavigator({
+ screenOptions: {
+ backBehavior: 'history',
+ },
+ screens: {
+ ProductList: ProductListScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(HomeTabs);
+
+export default function App() {
+ return ;
+}
+```
+
+Unlike `setParams`, the `pushParams` action does not merge the new params with the existing ones. Instead, it uses the new params object as-is and adds a new entry to the history stack.
+
+The action works in all navigators, such as stack, tab, and drawer. This allows adding a new entry to the history stack without needing to push a new screen instance.
+
+This can be useful in various scenarios:
+
+- A product listing page with filters, where changing filters should create a new history entry so that users can go back to previous filter states.
+- A screen with a custom modal component, where the modal is not a separate screen in the navigator, but its state should be reflected in the URL and history.
+
+If you want to push params for a particular route, you can add a `source` property referring to the route key:
+
+```js
+navigation.dispatch({
+ ...CommonActions.pushParams({ filter: 'popular' }),
+ source: route.key,
+});
+```
+
+If the `source` property is explicitly set to `undefined`, it'll push params for the focused route.
diff --git a/versioned_docs/version-8.x/navigation-events.md b/versioned_docs/version-8.x/navigation-events.md
index 1d3c6430a14..2aabd1458fb 100644
--- a/versioned_docs/version-8.x/navigation-events.md
+++ b/versioned_docs/version-8.x/navigation-events.md
@@ -279,7 +279,7 @@ const unsubscribe = navigation
});
```
-Here `'MyTabs'` refers to the value you pass in the `id` prop of the parent `Tab.Navigator` whose event you want to listen to.
+Here `'MyTabs'` refers to the name of the parent screen in the tab navigator whose event you want to listen to.
:::warning
diff --git a/versioned_docs/version-8.x/navigation-lifecycle.md b/versioned_docs/version-8.x/navigation-lifecycle.md
index d2a2317652b..17d6cfe804b 100755
--- a/versioned_docs/version-8.x/navigation-lifecycle.md
+++ b/versioned_docs/version-8.x/navigation-lifecycle.md
@@ -21,22 +21,25 @@ When we go back from `Profile` to `Home`, `Profile` is unmounted and its `useEff
Similar results can be observed (in combination) with other navigators as well. Consider a tab navigator with two tabs, where each tab is a stack navigator:
-
-
-
-```js name="Navigation lifecycle" snack
+```js name="Navigation lifecycle" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
+import {
+ createBottomTabNavigator,
+ createBottomTabScreen,
+} from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function SettingsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Settings');
React.useEffect(() => {
console.log('SettingsScreen mounted');
@@ -55,7 +58,7 @@ function SettingsScreen() {
}
function ProfileScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Profile');
React.useEffect(() => {
console.log('ProfileScreen mounted');
@@ -74,7 +77,7 @@ function ProfileScreen() {
}
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
React.useEffect(() => {
console.log('HomeScreen mounted');
@@ -93,7 +96,7 @@ function HomeScreen() {
}
function DetailsScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
React.useEffect(() => {
console.log('DetailsScreen mounted');
@@ -114,15 +117,23 @@ function DetailsScreen() {
// codeblock-focus-start
const SettingsStack = createNativeStackNavigator({
screens: {
- Settings: SettingsScreen,
- Profile: ProfileScreen,
+ Settings: createNativeStackScreen({
+ screen: SettingsScreen,
+ }),
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ }),
},
});
const HomeStack = createNativeStackNavigator({
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -131,8 +142,12 @@ const MyTabs = createBottomTabNavigator({
headerShown: false,
},
screens: {
- First: SettingsStack,
- Second: HomeStack,
+ First: createBottomTabScreen({
+ screen: SettingsStack,
+ }),
+ Second: createBottomTabScreen({
+ screen: HomeStack,
+ }),
},
});
// codeblock-focus-end
@@ -144,138 +159,6 @@ export default function App() {
}
```
-
-
-
-```js name="Navigation lifecycle" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-import { Button } from '@react-navigation/elements';
-
-function SettingsScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- console.log('SettingsScreen mounted');
-
- return () => console.log('SettingsScreen unmounted');
- }, []);
-
- return (
-
- Settings Screen
- navigation.navigate('Profile')}>
- Go to Profile
-
-
- );
-}
-
-function ProfileScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- console.log('ProfileScreen mounted');
-
- return () => console.log('ProfileScreen unmounted');
- }, []);
-
- return (
-
- Profile Screen
- navigation.navigate('Settings')}>
- Go to Settings
-
-
- );
-}
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- console.log('HomeScreen mounted');
-
- return () => console.log('HomeScreen unmounted');
- }, []);
-
- return (
-
- Home Screen
- navigation.navigate('Details')}>
- Go to Details
-
-
- );
-}
-
-function DetailsScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- console.log('DetailsScreen mounted');
-
- return () => console.log('DetailsScreen unmounted');
- }, []);
-
- return (
-
- Details Screen
- navigation.push('Details')}>
- Go to Details... again
-
-
- );
-}
-
-const SettingsStack = createNativeStackNavigator();
-const HomeStack = createNativeStackNavigator();
-const MyTabs = createBottomTabNavigator();
-
-// codeblock-focus-start
-function FirstScreen() {
- return (
-
-
-
-
- );
-}
-
-function SecondScreen() {
- return (
-
-
-
-
- );
-}
-
-function Root() {
- return (
-
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
@@ -290,10 +173,7 @@ React Navigation emits events to screen components that subscribe to them. We ca
Example:
-
-
-
-```js name="Focus and blur" snack
+```js name="Focus and blur" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -305,7 +185,7 @@ import { Button } from '@react-navigation/elements';
// codeblock-focus-start
function ProfileScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Profile');
React.useEffect(() => {
// highlight-start
@@ -336,7 +216,7 @@ function ProfileScreen() {
// codeblock-focus-end
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
@@ -378,110 +258,13 @@ export default function App() {
}
```
-
-
-
-```js name="Focus and blur" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-
-// codeblock-focus-start
-function ProfileScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- // highlight-start
- const unsubscribe = navigation.addListener('focus', () => {
- console.log('ProfileScreen focused');
- });
- // highlight-end
-
- return unsubscribe;
- }, [navigation]);
-
- React.useEffect(() => {
- // highlight-start
- const unsubscribe = navigation.addListener('blur', () => {
- console.log('ProfileScreen blurred');
- });
- // highlight-end
-
- return unsubscribe;
- }, [navigation]);
-
- return (
-
- Profile Screen
-
- );
-}
-// codeblock-focus-end
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- React.useEffect(() => {
- const unsubscribe = navigation.addListener('focus', () => {
- console.log('HomeScreen focused');
- });
-
- return unsubscribe;
- }, [navigation]);
-
- React.useEffect(() => {
- const unsubscribe = navigation.addListener('blur', () => {
- console.log('HomeScreen blurred');
- });
-
- return unsubscribe;
- }, [navigation]);
-
- return (
-
- Home Screen
- navigation.navigate('Profile')}>
- Go to Profile
-
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-function RootStack() {
- return (
-
-
-
-
- );
-}
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
See [Navigation events](navigation-events.md) for more details on the available events and the API usage.
For performing side effects, we can use the [`useFocusEffect`](use-focus-effect.md) hook instead of subscribing to events. It's like React's `useEffect` hook, but it ties into the navigation lifecycle.
Example:
-
-
-
-```js name="Focus effect" snack
+```js name="Focus effect" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -518,7 +301,7 @@ function ProfileScreen() {
// codeblock-focus-end
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -544,78 +327,6 @@ export default function App() {
}
```
-
-
-
-```js name="Focus effect" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { Button } from '@react-navigation/elements';
-// codeblock-focus-start
-import { useFocusEffect } from '@react-navigation/native';
-
-function ProfileScreen() {
- // highlight-start
- useFocusEffect(
- React.useCallback(() => {
- // Do something when the screen is focused
- console.log('ProfileScreen focus effect');
-
- return () => {
- // Do something when the screen is unfocused
- // Useful for cleanup functions
- console.log('ProfileScreen focus effect cleanup');
- };
- }, [])
- );
- // highlight-end
-
- return (
-
- Profile Screen
-
- );
-}
-// codeblock-focus-end
-
-function HomeScreen() {
- const navigation = useNavigation();
-
- return (
-
- Home Screen
- navigation.navigate('Profile')}>
- Go to Profile
-
-
- );
-}
-
-const Stack = createNativeStackNavigator();
-
-function RootStack() {
- return (
-
-
-
-
- );
-}
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
diff --git a/versioned_docs/version-8.x/navigation-object.md b/versioned_docs/version-8.x/navigation-object.md
index 42af46e61b2..54eb9921f0e 100755
--- a/versioned_docs/version-8.x/navigation-object.md
+++ b/versioned_docs/version-8.x/navigation-object.md
@@ -15,6 +15,8 @@ The `navigation` object contains various convenience functions that dispatch nav
- `reset` - replace the navigation state of the navigator with the given state
- `preload` - preload a screen in the background before navigating to it
- `setParams` - merge new params onto the route's params
+ - `replaceParams` - replace the route's params with new params
+ - `pushParams` - update params and push a new entry to history stack
- `dispatch` - send an action object to update the [navigation state](navigation-state.md)
- `setOptions` - update the screen's options
- `isFocused` - check whether the screen is focused
@@ -1381,6 +1383,25 @@ export default App;
+### `pushParams`
+
+The `pushParams` method lets us update the params (`route.params`) of the current screen and push a new entry to the history stack. Unlike `setParams` which merges the new params with the existing ones, `pushParams` uses the new params object as-is.
+
+`navigation.pushParams(params)`
+
+- `params` - _object_ - New params to use for the route.
+
+This is useful in scenarios like:
+
+- A product listing page with filters, where changing filters should create a new history entry so users can go back to previous filter states.
+- A screen with a custom modal component, where the modal is not a separate screen but its state should be reflected in the URL and history.
+
+```js
+navigation.pushParams({ filter: 'new' });
+```
+
+The action works in all navigators, including stack, tab, and drawer navigators.
+
### `setOptions`
The `setOptions` method lets us set screen options from within the component. This is useful if we need to use the component's props, state or context to configure our screen.
@@ -1848,37 +1869,39 @@ Don't use this method for rendering content as this will not trigger a re-render
This method returns the navigation object from the parent navigator that the current navigator is nested in. For example, if you have a stack navigator and a tab navigator nested inside the stack, then you can use `getParent` inside a screen of the tab navigator to get the navigation object passed from the stack navigator.
-It accepts an optional ID parameter to refer to a specific parent navigator. For example, if your screen is nested with multiple levels of nesting somewhere under a drawer navigator with the `id` prop as `"LeftDrawer"`, you can directly refer to it without calling `getParent` multiple times.
+It accepts an optional screen name parameter to refer to a specific parent screen. For example, if your screen is nested with multiple levels of nesting somewhere under a drawer navigator, you can directly refer to it by the name of the screen in the drawer navigator instead of calling `getParent` multiple times.
-To use an ID for a navigator, first pass a unique `id` prop:
+For example, consider the following structure:
-
-
-
-```js
-const Drawer = createDrawerNavigator({
- id: 'LeftDrawer',
+```js static2dynamic
+const LeftDrawer = createDrawerNavigator({
screens: {
- /* content */
+ Feed: {
+ screen: FeedScreen,
+ },
+ Messages: {
+ screen: MessagesScreen,
+ },
},
});
-```
-
-
-
-```js
-{/* .. */}
+const RootDrawer = createDrawerNavigator({
+ screens: {
+ Home: {
+ screen: HomeScreen,
+ },
+ Dashboard: {
+ screen: LeftDrawer,
+ },
+ },
+});
```
-
-
-
-Then when using `getParent`, instead of:
+Then when using `getParent` inside of `FeedScree`, instead of:
```js
// Avoid this
-const drawerNavigation = navigation.getParent().getParent();
+const drawerNavigation = navigation.getParent();
// ...
@@ -1889,16 +1912,18 @@ You can do:
```js
// Do this
-const drawerNavigation = navigation.getParent('LeftDrawer');
+const drawerNavigation = navigation.getParent('Dashboard');
// ...
drawerNavigation?.openDrawer();
```
-This approach allows components to not have to know the nesting structure of the navigators. So it's highly recommended that use an `id` when using `getParent`.
+In this case, `'Dashboard'` refers to the name of a parent screen of `Feed` that's used in the parent drawer navigator.
+
+This approach allows components to not have to know the nesting structure of the navigators. So it's highly recommended to use a screen name when using `getParent`.
-This method will return `undefined` if there is no matching parent navigator. Be sure to always check for `undefined` when using this method.
+This method will return `undefined` if there is no matching parent navigator.
### `getState`
diff --git a/versioned_docs/version-8.x/navigator.md b/versioned_docs/version-8.x/navigator.md
index f34638f4be2..00ba96a354f 100644
--- a/versioned_docs/version-8.x/navigator.md
+++ b/versioned_docs/version-8.x/navigator.md
@@ -48,46 +48,6 @@ Different navigators accept different configuration options. You can find the li
There is a set of common configurations that are shared across all navigators:
-### ID
-
-Optional unique ID for the navigator. This can be used with [`navigation.getParent`](navigation-object.md#getparent) to refer to this navigator in a child navigator.
-
-
-
-
-```js
-const MyStack = createNativeStackNavigator({
- // highlight-next-line
- id: 'RootStack',
- screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
- },
-});
-```
-
-
-
-
-```js
-const Stack = createNativeStackNavigator();
-
-function MyStack() {
- return (
-
-
-
-
- );
-}
-```
-
-
-
-
### Initial route name
The name of the route to render on the first load of the navigator.
@@ -312,13 +272,7 @@ function MyStack() {
### Router
-:::warning
-
-This API is experimental and may change in a minor release.
-
-:::
-
-Routers can be customized with the `UNSTABLE_router` prop on navigator to override how navigation actions are handled.
+Routers can be customized with the `router` prop on navigator to override how navigation actions are handled.
It takes a function that receives the original router and returns an object with overrides:
@@ -328,7 +282,7 @@ It takes a function that receives the original router and returns an object with
```js
const MyStack = createNativeStackNavigator({
// highlight-start
- UNSTABLE_router: (original) => ({
+ router: (original) => ({
getStateForAction(state, action) {
if (action.type === 'SOME_ACTION') {
// Custom logic
@@ -356,7 +310,7 @@ function MyStack() {
return (
({
+ router={(original) => ({
getStateForAction(state, action) {
if (action.type === 'SOME_ACTION') {
// Custom logic
@@ -378,7 +332,7 @@ function MyStack() {
-The function passed to `UNSTABLE_router` **must be a pure function and cannot reference outside dynamic variables**.
+The function passed to `router` **must be a pure function and cannot reference outside dynamic variables**.
The overrides object is shallow merged with the original router. So you don't need to specify all properties of the router, only the ones you want to override.
diff --git a/versioned_docs/version-8.x/nesting-navigators.md b/versioned_docs/version-8.x/nesting-navigators.md
index 4264cc57dcb..f07b07fc470 100755
--- a/versioned_docs/version-8.x/nesting-navigators.md
+++ b/versioned_docs/version-8.x/nesting-navigators.md
@@ -9,10 +9,7 @@ import TabItem from '@theme/TabItem';
Nesting navigators means rendering a navigator inside a screen of another navigator, for example:
-
-
-
-```js name="Nested navigators" snack
+```js name="Nested navigators" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -32,7 +29,7 @@ function ProfileScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -55,21 +52,27 @@ function MessagesScreen() {
// codeblock-focus-start
const HomeTabs = createBottomTabNavigator({
screens: {
- Feed: FeedScreen,
- Messages: MessagesScreen,
+ Feed: createBottomTabScreen({
+ screen: FeedScreen,
+ }),
+ Messages: createBottomTabScreen({
+ screen: MessagesScreen,
+ }),
},
});
const RootStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
// highlight-next-line
screen: HomeTabs,
options: {
headerShown: false,
},
- },
- Profile: ProfileScreen,
+ }),
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ }),
},
});
// codeblock-focus-end
@@ -81,86 +84,6 @@ export default function App() {
}
```
-
-
-
-```js name="Nested navigators" snack
-import * as React from 'react';
-import { Text, View } from 'react-native';
-import { NavigationContainer, useNavigation } from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-import { Button } from '@react-navigation/elements';
-
-function ProfileScreen() {
- return (
-
- Profile Screen
-
- );
-}
-
-function FeedScreen() {
- const navigation = useNavigation();
-
- return (
-
- Feed Screen
- navigation.navigate('Profile')}>
- Go to Profile
-
-
- );
-}
-
-function MessagesScreen() {
- return (
-
- Messages Screen
-
- );
-}
-
-const Tab = createBottomTabNavigator();
-const Stack = createNativeStackNavigator();
-
-// codeblock-focus-start
-function HomeTabs() {
- return (
-
-
-
-
- );
-}
-
-function RootStack() {
- return (
-
-
-
-
- );
-}
-// codeblock-focus-end
-
-export default function App() {
- return (
-
-
-
- );
-}
-```
-
-
-
-
In the above example, `HomeTabs` contains a tab navigator. It is also used for the `Home` screen in your stack navigator in `RootStack`. So here, a tab navigator is nested inside a stack navigator:
- `RootStack` (Stack navigator)
@@ -236,7 +159,7 @@ function ProfileScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -249,12 +172,12 @@ function FeedScreen() {
}
function MessagesScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
React.useEffect(() => {
// codeblock-focus-start
const unsubscribe = navigation
- .getParent('MyTabs')
+ .getParent('Home')
.addListener('tabPress', (e) => {
// Do something
alert('Tab pressed!');
@@ -279,7 +202,6 @@ const HomeStack = createNativeStackNavigator({
});
const RootTabs = createBottomTabNavigator({
- id: 'MyTabs',
screens: {
Home: {
screen: HomeStack,
@@ -318,7 +240,7 @@ function ProfileScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -331,12 +253,12 @@ function FeedScreen() {
}
function MessagesScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
React.useEffect(() => {
// codeblock-focus-start
const unsubscribe = navigation
- .getParent('MyTabs')
+ .getParent('Home')
.addListener('tabPress', (e) => {
// Do something
alert('Tab pressed!');
@@ -367,7 +289,7 @@ function HomeStack() {
function RootTabs() {
return (
-
+
-Here `'MyTabs'` refers to the value you pass in the `id` of the parent tab navigator whose event you want to listen to.
+Here `'Home'` refers to the name of the parent screen that contains the tab navigator whose event you want to listen to.
### Parent navigator's UI is rendered on top of child navigator
@@ -422,7 +344,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -438,7 +360,7 @@ function HomeScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -449,7 +371,7 @@ function FeedScreen() {
}
function MessagesScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
return (
@@ -499,7 +421,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -515,7 +437,7 @@ function HomeScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -526,7 +448,7 @@ function FeedScreen() {
}
function MessagesScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
return (
@@ -608,7 +530,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -631,7 +553,7 @@ function HomeScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -642,7 +564,7 @@ function FeedScreen() {
}
function MessagesScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
return (
@@ -691,7 +613,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -714,7 +636,7 @@ function HomeScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -725,7 +647,7 @@ function FeedScreen() {
}
function MessagesScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Messages');
return (
@@ -843,7 +765,7 @@ function ProfileScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
@@ -912,7 +834,7 @@ function ProfileScreen() {
}
function FeedScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Feed');
return (
diff --git a/versioned_docs/version-8.x/params.md b/versioned_docs/version-8.x/params.md
index 9bd5d6fb88a..a29715d8d18 100755
--- a/versioned_docs/version-8.x/params.md
+++ b/versioned_docs/version-8.x/params.md
@@ -11,10 +11,18 @@ Remember when I said "more on that later when we talk about `params`!"? Well, th
Now that we know how to create a stack navigator with some routes and [navigate between those routes](navigating.md), let's look at how we can pass data to routes when we navigate to them.
-There are two pieces to this:
+## Passing params
-1. Pass params to a route by putting them in an object as a second parameter to the `navigation.navigate` function: `navigation.navigate('RouteName', { /* params go here */ })`
-2. Read the params in your screen component: `route.params`.
+Params can be passed to screens while navigating to them via various navigation methods such as [`navigate`](navigation-actions.md#navigate), [`push`](stack-actions.md#push), [`jumpTo`](tab-actions.md#jumpto) etc. Typically, params are passed as the second argument to these methods.
+
+For example, to pass params while navigating to a screen using `navigate`:
+
+```js
+navigation.navigate('Details', {
+ itemId: 86,
+ otherParam: 'anything you want here',
+});
+```
:::note
@@ -22,19 +30,62 @@ We recommend that the params you pass are JSON-serializable. That way, you'll be
:::
-```js name="Passing params" snack
+## Reading params
+
+Params can be read from the `params` property of the `route` object. There are 2 main ways to access the `route` object:
+
+1. Your screen component automatically receives the `route` object as a prop:
+
+ ```js
+ // highlight-next-line
+ function DetailsScreen({ route }) {
+ // Access params from route.params
+ const { itemId, otherParam } = route.params;
+
+ return (
+ // ...
+ );
+ }
+ ```
+
+2. You can also use the [`useRoute`](use-route.md) hook to access the `route` object in any component inside your screen:
+
+ ```js
+ import { useRoute } from '@react-navigation/native';
+
+ function SomeComponent() {
+ // highlight-next-line
+ const route = useRoute('Details');
+
+ // Access params from route.params
+ const { itemId, otherParam } = route.params;
+
+ return (
+ // ...
+ );
+ }
+ ```
+
+ The `useRoute` hook takes the name of the current screen or any parent screen as an argument, and returns the route object containing the params for that screen.
+
+In this example, the `HomeScreen` passes params to the `DetailsScreen`. The `DetailsScreen` then reads and displays those params:
+
+```js name="Passing params" snack static2dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
// codeblock-focus-start
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -57,7 +108,7 @@ function HomeScreen() {
}
function DetailsScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Details');
/* 2. Get the param */
// highlight-next-line
@@ -90,8 +141,12 @@ function DetailsScreen({ route }) {
const RootStack = createNativeStackNavigator({
screens: {
- Home: HomeScreen,
- Details: DetailsScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Details: createNativeStackScreen({
+ screen: DetailsScreen,
+ }),
},
});
@@ -114,13 +169,13 @@ You can also pass some initial params to a screen. If you didn't specify any par
```js
-{
+createNativeStackScreen({
Details: {
screen: DetailsScreen,
// highlight-next-line
initialParams: { itemId: 42 },
},
-}
+});
```
@@ -140,11 +195,17 @@ You can also pass some initial params to a screen. If you didn't specify any par
## Updating params
-Screens can also update their params, like they can update their state. The `navigation.setParams` method lets you update the params of a screen. Refer to the [API reference for `setParams`](navigation-object.md#setparams) for more details.
+Screens can also update their params, like they can update their state. There are few ways to do this:
+
+- [`setParams`](navigation-actions.md#setparams) - updates the params by merging new params object with existing params
+- [`replaceParams`](navigation-actions.md#replaceparams) - replaces the params with new params object
+- [`pushParams`](navigation-actions.md#pushparams) - pushes a new entry in the history stack with the new params object
+
+All of these methods are available on the `navigation` object and they take a params object as their argument.
Basic usage:
-```js name="Updating params" snack
+```js name="Updating params" snack static2dynamic
import * as React from 'react';
import { Text, View } from 'react-native';
import {
@@ -155,7 +216,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
const { itemId } = route.params;
return (
@@ -180,10 +241,10 @@ function HomeScreen({ route }) {
const RootStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
initialParams: { itemId: 42 },
- },
+ }),
},
});
@@ -194,11 +255,9 @@ export default function App() {
}
```
-The `setParams` method merges the new params with the existing ones. To replace the existing params, you can use [`replaceParams`](navigation-object.md#replaceparams) instead.
-
:::note
-Avoid using `setParams` or `replaceParams` to update screen options such as `title` etc. If you need to update options, use [`setOptions`](navigation-object.md#setoptions) instead.
+Avoid using `setParams`, `replaceParams`, or `pushParams` to update screen options such as `title` etc. If you need to update options, use [`setOptions`](navigation-object.md#setoptions) instead.
:::
@@ -208,7 +267,7 @@ Params aren't only useful for passing some data to a new screen, but they can al
To achieve this, you can use the `popTo` method to go back to the previous screen as well as pass params to it:
-```js name="Passing params back" snack
+```js name="Passing params back" snack static2dynamic
import * as React from 'react';
import { Text, View, TextInput } from 'react-native';
import {
@@ -220,7 +279,7 @@ import { Button } from '@react-navigation/elements';
// codeblock-focus-start
function HomeScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
// Use an effect to monitor the update to params
// highlight-start
@@ -244,7 +303,7 @@ function HomeScreen({ route }) {
}
function CreatePostScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('CreatePost');
const [postText, setPostText] = React.useState('');
return (
@@ -272,8 +331,12 @@ function CreatePostScreen({ route }) {
const RootStack = createNativeStackNavigator({
screens: {
- Home: HomeScreen,
- CreatePost: CreatePostScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ CreatePost: createNativeStackScreen({
+ screen: CreatePostScreen,
+ }),
},
});
@@ -294,19 +357,25 @@ Here, after you press "Done", the home screen's `route.params` will be updated t
If you have nested navigators, you need to pass params a bit differently. For example, say you have a navigator inside the `More` screen and want to pass params to the `Settings` screen inside that navigator. Then you can pass params as the following:
-```js name="Passing params to nested screen" snack
+```js name="Passing params to nested screen" snack static2dynamic
import * as React from 'react';
import { Text, View, TextInput } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
+import {
+ createBottomTabNavigator,
+ createBottomTabScreen,
+} from '@react-navigation/bottom-tabs';
import { Button } from '@react-navigation/elements';
function SettingsScreen({ route }) {
- const navigation = useNavigation();
+ const navigation = useNavigation('Settings');
const { userId } = route.params;
return (
@@ -329,7 +398,7 @@ function ProfileScreen() {
}
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -353,15 +422,23 @@ function HomeScreen() {
const MoreStack = createNativeStackNavigator({
screens: {
- Settings: SettingsScreen,
- Profile: ProfileScreen,
+ Settings: createNativeStackScreen({
+ screen: SettingsScreen,
+ }),
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ }),
},
});
const RootTabs = createBottomTabNavigator({
screens: {
- Home: HomeScreen,
- More: MoreStack,
+ Home: createBottomTabScreen({
+ screen: HomeScreen,
+ }),
+ More: createBottomTabScreen({
+ screen: MoreStack,
+ }),
},
});
@@ -440,7 +517,7 @@ Some examples of what should be in params are:
- [`navigate`](navigation-actions.md#navigate) and [`push`](stack-actions.md#push) accept an optional second argument to let you pass parameters to the route you are navigating to. For example: `navigation.navigate('RouteName', { paramName: 'value' })`.
- You can read the params through [`route.params`](route-object.md) inside a screen
-- You can update the screen's params with [`navigation.setParams`](navigation-object.md#setparams) or [`navigation.replaceParams`](navigation-object.md#replaceparams)
+- You can update the screen's params with [`navigation.setParams`](navigation-object.md#setparams), [`navigation.replaceParams`](navigation-object.md#replaceparams) or [`navigation.pushParams`](navigation-object.md#pushparams)
- Initial params can be passed via the [`initialParams`](screen.md#initial-params) prop on `Screen` or in the navigator config
- State such as sort order, filters etc. should be kept in params so that the state is reflected in the URL and can be shared/bookmarked.
- Params should contain the least amount of data required to identify a screen; for most cases, this means passing the ID of an object instead of passing a full object.
diff --git a/versioned_docs/version-8.x/screen-options.md b/versioned_docs/version-8.x/screen-options.md
index 9463726e457..0a9a89af8e2 100644
--- a/versioned_docs/version-8.x/screen-options.md
+++ b/versioned_docs/version-8.x/screen-options.md
@@ -56,18 +56,18 @@ function ProfileScreen() {
// codeblock-focus-start
const RootStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: {
title: 'Awesome app',
},
- },
- Profile: {
+ }),
+ Profile: createNativeStackScreen({
screen: ProfileScreen,
options: {
title: 'My profile',
},
- },
+ }),
},
});
@@ -84,7 +84,7 @@ You can also pass a function to `options`. The function will receive the [`navig
```js static2dynamic
const RootStack = createNativeStackNavigator({
screens: {
- Home: {
+ Home: createNativeStackScreen({
screen: HomeScreen,
options: ({ navigation }) => ({
title: 'Awesome app',
@@ -92,7 +92,7 @@ const RootStack = createNativeStackNavigator({
navigation.toggleDrawer()} />;
},
}),
- },
+ }),
},
});
```
@@ -114,7 +114,10 @@ import {
useNavigation,
createStaticNavigation,
} from '@react-navigation/native';
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
// codeblock-focus-start
const RootStack = createNativeStackNavigator({
@@ -233,8 +236,12 @@ Similar to `options`, you can also pass a function to `screenOptions`. The funct
```js
const Stack = createNativeStackNavigator({
screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ }),
},
groups: {
Modal: {
@@ -243,8 +250,12 @@ const Stack = createNativeStackNavigator({
headerLeft: () => ,
},
screens: {
- Settings: Settings,
- Share: Share,
+ Settings: createNativeStackScreen({
+ screen: Settings,
+ }),
+ Share: createNativeStackScreen({
+ screen: Share,
+ }),
},
},
},
@@ -287,8 +298,12 @@ const RootStack = createNativeStackNavigator({
},
},
screens: {
- Home: HomeScreen,
- Profile: ProfileScreen,
+ Home: createNativeStackScreen({
+ screen: HomeScreen,
+ }),
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ }),
},
});
```
@@ -299,7 +314,10 @@ Similar to `options`, you can also pass a function to `screenOptions`. The funct
import * as React from 'react';
import { View } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import {
+ createBottomTabNavigator,
+ createBottomTabScreen,
+} from '@react-navigation/bottom-tabs';
import { MaterialCommunityIcons } from '@expo/vector-icons';
// codeblock-focus-start
@@ -321,8 +339,12 @@ const MyTabs = createBottomTabNavigator({
},
}),
screens: {
- Home: EmptyScreen,
- Profile: EmptyScreen,
+ Home: createBottomTabScreen({
+ screen: EmptyScreen,
+ }),
+ Profile: createBottomTabScreen({
+ screen: EmptyScreen,
+ }),
},
});
// codeblock-focus-end
diff --git a/versioned_docs/version-8.x/static-configuration.md b/versioned_docs/version-8.x/static-configuration.md
index a272bef5a71..c71211f50af 100644
--- a/versioned_docs/version-8.x/static-configuration.md
+++ b/versioned_docs/version-8.x/static-configuration.md
@@ -121,6 +121,42 @@ const RootStack = createNativeStackNavigator({
The configuration object for a screen accepts the [properties described in the Screen page](screen.md). In addition, the following properties are available when using static configuration:
+#### `createXScreen`
+
+Each navigator exports a helper function to create screen configurations with proper TypeScript types. These helpers enable type inference for the params in the configuration.
+
+Example usage:
+
+```js
+import {
+ createNativeStackNavigator,
+ createNativeStackScreen,
+} from '@react-navigation/native-stack';
+
+const Stack = createNativeStackNavigator({
+ screens: {
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ options: ({ route }) => {
+ const userId = route.params.userId;
+
+ return {
+ title: `${userId}'s profile`,
+ };
+ },
+ }),
+ },
+});
+```
+
+Each navigator exports its own helper function:
+
+- `createNativeStackScreen` from `@react-navigation/native-stack`
+- `createStackScreen` from `@react-navigation/stack`
+- `createBottomTabScreen` from `@react-navigation/bottom-tabs`
+- `createDrawerScreen` from `@react-navigation/drawer`
+- `createMaterialTopTabScreen` from `@react-navigation/material-top-tabs`
+
#### `linking`
[Linking configuration](configuring-links.md) for the screen. It can be either a string for a path or an object with the linking configuration:
diff --git a/versioned_docs/version-8.x/tab-view.md b/versioned_docs/version-8.x/tab-view.md
index b1e13b3d2c2..2e11ed98084 100644
--- a/versioned_docs/version-8.x/tab-view.md
+++ b/versioned_docs/version-8.x/tab-view.md
@@ -205,7 +205,9 @@ props.jumpTo('albums');
All the scenes rendered with `SceneMap` are optimized using `React.PureComponent` and don't re-render when parent's props or states change. If you need more control over how your scenes update (e.g. - triggering a re-render even if the `navigationState` didn't change), use `renderScene` directly instead of using `SceneMap`.
-**IMPORTANT:** **Do not** pass inline functions to `SceneMap`, for example, don't do the following:
+:::warning
+
+**Do not** pass inline functions to `SceneMap`, for example, don't do the following:
```js
SceneMap({
@@ -214,6 +216,8 @@ SceneMap({
});
```
+:::
+
Always define your components elsewhere in the top level of the file. If you pass inline functions, it'll re-create the component every render, which will cause the entire route to unmount and remount every change. It's very bad for performance and will also cause any local state to be lost.
If you need to pass additional props, use a custom `renderScene` function:
@@ -304,6 +308,72 @@ String indicating whether the keyboard gets dismissed in response to a drag gest
Boolean indicating whether to enable swipe gestures. Swipe gestures are enabled by default. Passing `false` will disable swipe gestures, but the user can still switch tabs by pressing the tab bar.
+##### `renderAdapter`
+
+A function that returns a custom adapter for rendering pages. By default, `react-native-tab-view` uses [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view) for rendering pages on Android and iOS. However, it may not be suitable for all use cases.
+
+You can use built-in adapters or create your own custom adapter. For example, you can use `ScrollViewAdapter` to use a `ScrollView` for rendering pages:
+
+```js
+import React from 'react';
+import { TabView, ScrollViewAdapter } from 'react-native-tab-view';
+
+export default function TabViewExample() {
+ const [index, setIndex] = React.useState(0);
+
+ return (
+
+ );
+}
+```
+
+The following built-in adapters are available:
+
+- `PagerViewAdapter`: Uses [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view) for rendering pages (default on Android & iOS).
+- `PanResponderAdapter`: Uses [`PanResponder`](https://reactnative.dev/docs/panresponder) for handling gestures (default on Web and other platforms).
+- `ScrollViewAdapter`: Uses [`ScrollView`](https://reactnative.dev/docs/scrollview) for rendering pages.
+
+You can also create your own custom adapter by implementing the required interface:
+
+```ts
+function MyAdapter({ navigationState, children }: AdapterProps) {
+ const { index, routes } = navigationState;
+
+ // Animated.Value containing the current position (index + offset)
+ // This should be updated as the user swipes between pages
+ const [position] = useState(() => new Animated.Value(index));
+
+ const subscribe = useCallback(
+ (callback: (event: { type: 'enter'; index: number }) => void) => {
+ // Subscribe to `enter` events and call the callback when the page comes into view
+ // This is used to render lazy loaded pages only when they come into view
+ },
+ []
+ );
+
+ const jumpTo = useCallback((key: string) => {
+ // Function to jump to a specific page by key of the route
+ }, []);
+
+ return children({
+ position,
+ subscribe,
+ jumpTo,
+ render: (children) => {
+ // Render the pages based on the `children` array
+ // The `children` array contains react elements for each route in the routes array
+ },
+ });
+}
+```
+
+Check out the [source code of the built-in adapters](https://github.com/react-navigation/react-navigation/tree/main/packages/react-native-tab-view/src) for reference.
+
#### `animationEnabled`
Enables animation when changing tab. By default it's true.
diff --git a/versioned_docs/version-8.x/themes.md b/versioned_docs/version-8.x/themes.md
index 9d431ccded6..ec49887e198 100755
--- a/versioned_docs/version-8.x/themes.md
+++ b/versioned_docs/version-8.x/themes.md
@@ -326,6 +326,50 @@ const MyTheme = {
Providing a theme will take care of styling of all the official navigators. React Navigation also provides several tools to help you make your customizations of those navigators and the screens within the navigators can use the theme too.
+## Using platform colors
+
+Theme colors support `ColorValue` type, which means you can use `PlatformColor`, `DynamicColorIOS` on native, and CSS custom properties on Web for more flexibility.
+
+Example theme using `PlatformColor`:
+
+```js
+import { Platform, PlatformColor } from 'react-native';
+import { DefaultTheme } from '@react-navigation/native';
+
+const MyTheme = {
+ ...DefaultTheme,
+ colors: Platform.select({
+ ios: () => ({
+ primary: PlatformColor('systemRed'),
+ background: PlatformColor('systemGroupedBackground'),
+ card: PlatformColor('tertiarySystemBackground'),
+ text: PlatformColor('label'),
+ border: PlatformColor('separator'),
+ notification: PlatformColor('systemRed'),
+ }),
+ android: () => ({
+ primary: PlatformColor('@android:color/system_primary_light'),
+ background: PlatformColor(
+ '@android:color/system_surface_container_light'
+ ),
+ card: PlatformColor('@android:color/system_background_light'),
+ text: PlatformColor('@android:color/system_on_surface_light'),
+ border: PlatformColor('@android:color/system_outline_variant_light'),
+ notification: PlatformColor('@android:color/holo_red_light'),
+ }),
+ default: () => DefaultTheme.colors,
+ })(),
+};
+```
+
+This allows your app's navigation UI to automatically adapt to system theme changes and use native colors.
+
+:::note
+
+When using dynamic colors like `PlatformColor` or `DynamicColorIOS`, React Navigation cannot automatically adjust colors in some scenarios (e.g., adjusting the text color based on background color). In these cases, it will fall back to pre-defined colors according to the theme.
+
+:::
+
## Built-in themes
As operating systems add built-in support for light and dark modes, supporting dark mode is less about keeping hip to trends and more about conforming to the average user expectations for how apps should work. In order to provide support for light and dark mode in a way that is reasonably consistent with the OS defaults, these themes are built in to React Navigation.
diff --git a/versioned_docs/version-8.x/typescript.md b/versioned_docs/version-8.x/typescript.md
index 72fd891716a..da1136cca14 100755
--- a/versioned_docs/version-8.x/typescript.md
+++ b/versioned_docs/version-8.x/typescript.md
@@ -17,81 +17,222 @@ First, make sure you have the following configuration in your `tsconfig.json` un
+## Setting up the types
+
There are 2 steps to configure TypeScript with the static API:
-1. Each screen component needs to specify the type of the [`route.params`](params.md) prop that it accepts. The `StaticScreenProps` type makes it simpler:
+### Specify the root navigator's type
+
+For the type-inference to work, React Navigation needs to know the type of the root navigator in your app. To do this, you can declare a module augmentation for `@react-navigation/core` and extend the `RootNavigator` interface with the type of your root navigator.
+
+```ts
+const HomeTabs = createBottomTabNavigator({
+ screens: {
+ Feed: FeedScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeTabs,
+ },
+});
+
+// highlight-next-line
+type RootStackType = typeof RootStack;
+
+// highlight-start
+declare module '@react-navigation/core' {
+ interface RootNavigator extends RootStackType {}
+}
+// highlight-end
+```
+
+This is needed to type-check hooks such as [`useNavigation`](use-navigation.md), [`useRoute`](use-route.md), [`useNavigationState`](use-navigation-state.md) etc.
+
+### Specify param types for screens
+
+After setting up the type for the root navigator, all we need to do is specify the type of params that our screens accept.
+
+This can be done in 2 ways:
+
+1. The type annotation for the component specified in `screen`:
```ts
import type { StaticScreenProps } from '@react-navigation/native';
// highlight-start
- type Props = StaticScreenProps<{
- username: string;
- }>;
+ type ProfileParams = {
+ userId: string;
+ };
// highlight-end
- function ProfileScreen({ route }: Props) {
+ // highlight-next-line
+ function ProfileScreen({ route }: StaticScreenProps) {
// ...
}
```
-2. Generate the `ParamList` type for the root navigator and specify it as the default type for the `RootParamList` type:
+ In the above example, the type of `route.params` is `{ userId: string }` based on the type annotation in `StaticScreenProps`.
+
+ If you aren't using the `route` object in the component, you can specify the `props` as `_` to avoid unused variable warnings:
```ts
- import type { StaticParamList } from '@react-navigation/native';
+ // highlight-next-line
+ function ProfileScreen(_: StaticScreenProps) {
+ // ...
+ }
+ ```
- const HomeTabs = createBottomTabNavigator({
- screens: {
- Feed: FeedScreen,
- Profile: ProfileScreen,
- },
- });
+2. The path pattern specified in the linking config (e.g. for `linking: 'profile/:userId'`, the type of `route.params` is `{ userId: string }`). The type can be further customized by using a [`parse` function in the linking config](configuring-links.md#passing-params):
- const RootStack = createNativeStackNavigator({
- screens: {
- Home: HomeTabs,
+ ```ts
+ linking: {
+ path: 'profile/:userId',
+ parse: {
+ userId: (id) => parseInt(id, 10),
},
- });
+ },
+ ```
- // highlight-next-line
- type RootStackParamList = StaticParamList;
+ The above example would make the type of `route.params` be `{ userId: number }` since the `parse` function converts the string from the URL to a number.
- // highlight-start
- declare global {
- namespace ReactNavigation {
- interface RootParamList extends RootStackParamList {}
- }
- }
- // highlight-end
- ```
+If both `screen` and `linking` specify params, the final type of `route.params` is the intersection of both types.
+
+This is how the complete example would look like:
+
+```ts
+const MyStack = createNativeStackNavigator({
+ screens: {
+ // highlight-start
+ Profile: createNativeStackScreen({
+ screen: ProfileScreen,
+ linking: {
+ path: 'profile/:userId',
+ parse: {
+ userId: (id) => parseInt(id, 10),
+ },
+ },
+ }),
+ // highlight-end
+ },
+});
+```
+
+If your app supports deep linking or runs on the Web, it is recommended to specify params that appear in the path pattern in the linking config. Any additional params (e.g. query params) can be specified in the component's props.
+
+If you have specified the params in `linking`, it's recommended to not specify them again in the component's props, and use `useRoute('ScreenName')` instead to get the correctly typed `route` object.
+
+The `createXScreen` helper functions enable type inference in screen configuration callbacks like `options`, `listeners`, etc. Each navigator exports its own version of the helper function:
+
+- `createNativeStackScreen` from `@react-navigation/native-stack`
+- `createStackScreen` from `@react-navigation/stack`
+- `createBottomTabScreen` from `@react-navigation/bottom-tabs`
+- `createDrawerScreen` from `@react-navigation/drawer`
+- `createMaterialTopTabScreen` from `@react-navigation/material-top-tabs`
- This is needed to type-check the [`useNavigation`](use-navigation.md) hook.
+See [Static configuration](static-configuration.md#createxscreen) for more details.
-## Navigator specific types
+## Using typed hooks
-Generally, we recommend using the default types for the [`useNavigation`](use-navigation.md) prop to access the navigation object in a navigator-agnostic manner. However, if you need to use navigator-specific APIs, e.g. `setOptions` to update navigator options, `push`, `pop`, `popTo` etc. with stacks, `openDrawer`, `closeDrawer` etc. with drawer and so on, you need to manually annotate [`useNavigation`](use-navigation.md):
+The [`useRoute`](use-route.md), [`useNavigation`](use-navigation.md), and [`useNavigationState`](use-navigation-state.md) hooks accept the name of the current screen or any parent screen where it's nested as an argument to infer the correct types.
+
+Once the types are set up, these hooks are automatically typed based on the name of the screen passed to them.
+
+With `useRoute`:
```ts
-import type { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
+function ProfileScreen() {
+ const route = useRoute('Profile');
-type BottomTabParamList = StaticParamList;
-type ProfileScreenNavigationProp = BottomTabNavigationProp<
- BottomTabParamList,
- 'Profile'
->;
+ // The params are correctly typed here
+ const { userId } = route.params;
-// ...
+ // ...
+}
+```
-const navigation = useNavigation();
+With `useNavigation`:
+
+```ts
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ // Helpers like `push` are correctly typed here
+ navigation.push('Feed');
+
+ // ...
+}
```
-Similarly, you can import `NativeStackNavigationProp` from [`@react-navigation/native-stack`](native-stack-navigator.md), `StackNavigationProp` from [`@react-navigation/stack`](stack-navigator.md), `DrawerNavigationProp` from [`@react-navigation/drawer`](drawer-navigator.md) etc.
+With `useNavigationState`:
-:::danger
+```ts
+function ProfileScreen() {
+ const focusedRouteName = useNavigationState(
+ 'Profile',
+ // The state is correctly typed here
+ (state) => state.routes[state.index].name
+ );
-Annotating [`useNavigation`](use-navigation.md) this way is not type-safe since we can't guarantee that the type you provided matches the type of the navigator. So try to keep manual annotations to a minimum and use the default types instead.
+ // The `focusedRouteName` type is one of the route names
+ // defined in the navigator where `Profile` is defined
+ console.log(focusedRouteName);
-:::
+ // ...
+}
+```
+
+It's also possible to use these hooks without specifying the screen name - which can be useful in re-usable components that can be used across multiple screens. In this case, different things happen based on the hook.
+
+The `useRoute` hook returns a union of all routes in the app, and can be narrowed down using type guards:
+
+```ts
+function Header() {
+ const route = useRoute();
+
+ // The route is an union of all routes in the app
+ console.log(route.name);
+
+ // It's possible to narrow down the type using type guards
+ if (route.name === 'Profile') {
+ // Here route.params is correctly typed
+ const { userId } = route.params;
+ }
+
+ // ...
+}
+```
+
+The `useNavigation` hook returns a generic navigation object that refers to the root navigator. This means that any navigation actions can be called as if they are used in a screen of the root navigator:
+
+```ts
+function Header() {
+ const navigation = useNavigation();
+
+ // A generic navigation object that refers to the root navigator
+ navigation.navigate('Profile', { userId: '123' });
+
+ // ...
+}
+```
+
+The `useNavigationState` hook returns a generic navigation state without any navigator-specific types:
+
+```ts
+function Header() {
+ const focusedRouteName = useNavigationState((state) => {
+ // The state is a generic navigation state
+ return state.routes[state.index].name;
+ });
+
+ // The `focusedRouteName` type is `string`
+ console.log(focusedRouteName);
+
+ // ...
+}
+```
## Nesting navigator using dynamic API
@@ -110,13 +251,15 @@ function HomeTabs() {
}
const RootStack = createStackNavigator({
- Home: HomeTabs,
+ screens: {
+ Home: HomeTabs,
+ },
});
```
-Here, the `HomeTabs` component is defined using the dynamic API. This means that when we create the param list for the root navigator with `StaticParamList`, it won't know about the screens defined in the nested navigator. To fix this, we'd need to specify the param list for the nested navigator explicitly.
+Here, the `HomeTabs` component is defined using the dynamic API. This means that React Navigation won't know about the screens defined in the nested navigator and the types for those screens. To fix this, we'd need to specify the types for the nested navigator explicitly.
-This can be done by using the type of the [`route`](route-object.md) prop that the screen component receives:
+This can be done by annotating the type of the [`route`](route-object.md) prop that the screen component receives:
```ts
type HomeTabsParamList = {
@@ -141,7 +284,9 @@ function HomeTabs(_: HomeTabsProps) {
}
```
-Now, when using `StaticParamList`, it will include the screens defined in the nested navigator.
+Here the `HomeTabsParamList` type defines the mapping of route names in the tab navigator to the types of their params. We then use the `NavigatorScreenParams` utility to say that these are the screens in a nested navigator in the `HomeTabs` component.
+
+Now, React Navigation knows about the screens in the nested navigator and their params, and the types can be inferred with hooks such as `useRoute`.
@@ -200,12 +345,6 @@ The type containing the mapping must be a type alias (e.g. `type RootStackParamL
:::
-If you have an [`id`](./navigator.md#id) prop for your navigator, you will also need to pass it as a generic:
-
-```tsx
-const RootStack = createStackNavigator();
-```
-
## Type checking screens
To typecheck our screens, we need to annotate the `navigation` and the `route` props received by a screen. The navigator packages in React Navigation export generic types to define types for both the `navigation` and `route` props from the corresponding navigator.
@@ -224,17 +363,10 @@ type RootStackParamList = {
type Props = NativeStackScreenProps;
```
-The type takes 3 generics:
+The type takes 2 generics:
- The param list object we defined earlier
- The name of the route the screen belongs to
-- The ID of the navigator (optional)
-
-If you have an [`id`](./navigator.md#id) prop for your navigator, you can do:
-
-```ts
-type Props = NativeStackScreenProps;
-```
This allows us to type check route names and params which you're navigating using [`navigate`](navigation-object.md#navigate), [`push`](stack-actions.md#push) etc. The name of the current route is necessary to type check the params in `route.params` and when you call [`setParams`](navigation-actions#setparams) or [`replaceParams`](navigation-actions#replaceparams).
@@ -364,34 +496,72 @@ type ProfileScreenNavigationProp = CompositeNavigationProp<
>;
```
-## Annotating `useNavigation`
+## Annotating hooks
-:::danger
+The [`useRoute`](use-route.md), [`useNavigation`](use-navigation.md), and [`useNavigationState`](use-navigation-state.md) hooks accept the name of the current screen or any parent screen where it's nested as an argument for limited type inference in dynamic API after [specifying root navigator type](#specifying-root-navigator-type).
-Annotating `useNavigation` isn't type-safe because the type parameter cannot be statically verified.
-Prefer [specifying a default type](#specifying-default-types-for-usenavigation-link-ref-etc) instead.
+With `useRoute`:
-:::
+```ts
+function ProfileScreen() {
+ const route = useRoute('Profile');
-To annotate the `navigation` object that we get from [`useNavigation`](use-navigation.md), we can use a type parameter:
+ // The params are correctly typed here
+ const { userId } = route.params;
+
+ // ...
+}
+```
+
+With `useNavigation`:
```ts
-const navigation = useNavigation();
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ // Helpers like `getState` are correctly typed here
+ const state = navigation.getState();
+
+ // ...
+}
```
-## Annotating `useRoute`
+This will automatically infer the type for methods such as `getState`, `setParams` etc. However, it doesn't include navigator-specific types, and they cannot be automatically inferred when using the dynamic configuration.
+
+So if we want to use a navigator-specific method (e.g. `push` from stack navigator), we need to annotate the type of the returned `navigation` object.
+
+This can be done using [type assertion](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions) with the `as` keyword:
+
+```ts
+function ProfileScreen() {
+ const navigation = useNavigation('Profile') as ProfileScreenNavigationProp;
+
+ // ...
+}
+```
:::danger
-Annotating `useRoute` isn't type-safe because the type parameter cannot be statically verified.
-Prefer using the [`route` object](route-object.md) from the screen component's props instead when possible. Use `useRoute` for generic code that doesn't need specific route type.
+Annotating `useNavigation` isn't type-safe because we cannot verify that the provided type matches the actual navigators.
:::
-To annotate the `route` object that we get from [`useRoute`](use-route.md), we can use a type parameter:
+With `useNavigationState`:
```ts
-const route = useRoute();
+function ProfileScreen() {
+ const focusedRouteName = useNavigationState(
+ 'Profile',
+ // The state is correctly typed here
+ (state) => state.routes[state.index].name
+ );
+
+ // The `focusedRouteName` type is one of the route names
+ // defined in the navigator where `Profile` is defined
+ console.log(focusedRouteName);
+
+ // ...
+}
```
## Annotating `options` and `screenOptions`
@@ -425,6 +595,25 @@ const options = ({ route }: StackOptionsArgs): StackNavigationOptions => {
};
```
+If you want to annotate the type of params in the `route` object, you can use pass the param list and route name as generics to the `StackOptionsArgs` type:
+
+```ts
+import type {
+ StackNavigationOptions,
+ StackOptionsArgs,
+} from '@react-navigation/stack';
+
+const options = ({
+ route,
+}: StackOptionsArgs): StackNavigationOptions => {
+ const { userId } = route.params;
+
+ return {
+ headerTitle: `Profile of ${userId}`,
+ };
+};
+```
+
## Annotating `ref` on `NavigationContainer`
If you use the `createNavigationContainerRef()` method to create the ref, you can annotate it to type-check navigation actions:
@@ -471,23 +660,30 @@ const navigationRef =
React.createRef>();
```
-## Specifying default types for `useNavigation`, `Link`, `ref` etc
+## Specifying root navigator type
-Instead of manually annotating these APIs, you can specify a global type for your root navigator which will be used as the default type.
+You can specify the type for your root navigator which will enable automatic type inference (with limitations) for [`useRoute`](use-route.md), [`useNavigation`](use-navigation.md), [`useNavigationState`](use-navigation-state.md), [`Link`](link.md), [`ref`](navigation-container.md#ref), [`linking`](navigation-container.md#linking) etc.
-To do this, you can add this snippet somewhere in your codebase:
+To do this, you can use module augmentation for `@react-navigation/core` and extend the `RootNavigator` interface with the type of your root navigator.
-```js
-declare global {
- namespace ReactNavigation {
- interface RootParamList extends RootStackParamList {}
- }
+```ts
+const RootStack = createNativeStackNavigator();
+
+function App() {
+ // ...
}
-```
-The `RootParamList` interface lets React Navigation know about the params accepted by your root navigator. Here we extend the type `RootStackParamList` because that's the type of params for our stack navigator at the root. The name of this type isn't important.
+// highlight-next-line
+type RootStackType = typeof RootStack;
-Specifying this type is important if you heavily use [`useNavigation`](use-navigation.md), [`Link`](link.md) etc. in your app since it'll ensure type-safety. It will also make sure that you have correct nesting on the [`linking`](navigation-container.md#linking) prop.
+// highlight-start
+declare module '@react-navigation/core' {
+ interface RootNavigator extends RootStackType {}
+}
+// highlight-end
+```
+
+Here `RootStack` refers to the navigator used at the root of your app.
## Organizing types
@@ -526,32 +722,34 @@ export type HomeTabScreenProps =
BottomTabScreenProps,
RootStackScreenProps
>;
-
-declare global {
- namespace ReactNavigation {
- interface RootParamList extends RootStackParamList {}
- }
-}
```
-Now, when annotating your components, you can write:
+Then, you'd set up the global type for your root navigator in the same file where your root navigator is defined:
```ts
-import type { HomeTabScreenProps } from './navigation/types';
+import { createStackNavigator } from '@react-navigation/stack';
+import type { RootStackParamList } from './navigation/types';
-function PopularScreen({ navigation, route }: HomeTabScreenProps<'Popular'>) {
+const RootStack = createStackNavigator();
+
+function App() {
// ...
}
+
+// Specify the global type for the root navigator
+type RootStackType = typeof RootStack;
+
+declare module '@react-navigation/core' {
+ interface RootNavigator extends RootStackType {}
+}
```
-If you're using hooks such as [`useRoute`](use-route.md), you can write:
+Now, when annotating your components, you can write:
```ts
import type { HomeTabScreenProps } from './navigation/types';
-function PopularScreen() {
- const route = useRoute['route']>();
-
+function PopularScreen({ navigation, route }: HomeTabScreenProps<'Popular'>) {
// ...
}
```
diff --git a/versioned_docs/version-8.x/upgrading-from-6.x.md b/versioned_docs/version-8.x/upgrading-from-6.x.md
deleted file mode 100755
index fd5c971cedf..00000000000
--- a/versioned_docs/version-8.x/upgrading-from-6.x.md
+++ /dev/null
@@ -1,1023 +0,0 @@
----
-id: upgrading-from-6.x
-title: Upgrading from 6.x
-sidebar_label: Upgrading from 6.x
----
-
-React Navigation 7 focuses on streamlining the API to avoid patterns that can cause bugs. This means deprecating some of the legacy behavior kept for backward compatibility reasons.
-
-This guides lists all the breaking changes and new features in React Navigation 7 that you need to be aware of when upgrading from React Navigation 6.
-
-## Minimum Requirements
-
-- `react-native` >= 0.72.0
-- `expo` >= 52 (if you use [Expo Go](https://expo.dev/go))
-- `typescript` >= 5.0.0 (if you use TypeScript)
-
-## Breaking changes
-
-### Changes to the `navigate` action
-
-#### The `navigate` method no longer navigates to screen in a nested child navigator
-
-Due to backward compatibility reasons, React Navigation 5 and 6 support navigating to a screen in a nested child navigator with `navigation.navigate(ScreenName)` syntax. But this is problematic:
-
-- It only works if the navigator is already mounted - making navigation coupled to other logic.
-- It doesn't work with the TypeScript types.
-
-Due to these issues, we have a special API to navigate to a nested screen (`navigation.navigate(ParentScreenName, { screen: ScreenName })`).
-
-From these release, this is no longer the default behavior. If you're relying on this behavior in your app, you can pass the [`navigationInChildEnabled`](navigation-container.md#navigationinchildenabled) prop to `NavigationContainer` to keep the behavior until you are able to migrate:
-
-```jsx
-{/* ... */}
-```
-
-The `navigationInChildEnabled` prop will be removed in the next major.
-
-See [`navigate`](navigation-object.md#navigate) for updated usage.
-
-#### The `navigate` method no longer goes back, use `popTo` instead
-
-Previously, `navigate` method navigated back if the screen already exists in the stack. We have seen many people get confused by this behavior.
-
-To avoid this confusion, we have removed the going back behavior from `navigate` and added a [new method `popTo`](stack-actions.md#popto) to explicitly go back to a specific screen in the stack:
-
-```diff lang=js
-- navigation.navigate('PreviousScreen', { foo: 42 });
-+ navigation.popTo('PreviousScreen', { foo: 42 });
-```
-
-The methods now behave as follows:
-
-- `navigate(screenName)` will stay on the current screen if the screen is already focused, otherwise push a new screen to the stack.
-- `popTo(screenName)` will go back to the screen if it exists in the stack, otherwise pop the current screen and add this screen to the stack.
-
-See [`popTo`](stack-actions.md#popto) for more details.
-
-To achieve a behavior similar to before with `navigate`, you can use specify `pop: true` in the options:
-
-```diff lang=js
-- navigation.navigate('PreviousScreen', { foo: 42 });
-+ navigation.navigate('PreviousScreen', { foo: 42 }, { pop: true });
-```
-
-To help with the migration, we have added a new method called `navigateDeprecated` which will behave like the old `navigate` method. You can replace your current `navigate` calls with [`navigateDeprecated`](navigation-object.md#navigatedeprecated) to gradually migrate to the new behavior:
-
-```diff lang=js
-- navigation.navigate('SomeScreen');
-+ navigation.navigateDeprecated('SomeScreen');
-```
-
-The `navigateDeprecated` method will be removed in the next major.
-
-#### The `navigate` method no longer accepts a `key` option
-
-Previously, you could specify a route `key` to navigate to, e.g.:
-
-```js
-navigation.navigate({ key: 'someuniquekey' })`
-```
-
-It's problematic since:
-
-- `key` is an internal implementation detail and created by the library internally - which makes it weird to use.
-- None of the other actions support such usage.
-- Specifying a `key` is not type-safe, making it easy to cause bugs.
-
-In React Navigation 5, we added the [`getId`](screen.md#id) prop which can be used for similar use cases - and gives users full control since they provide the ID and it's not autogenerated by the library.
-
-So the `key` option is now being removed from the `navigate` action.
-
-See [`navigate`](navigation-object.md#navigate) for updated usage.
-
-### Changes to `NavigationContainer`
-
-#### The `onReady` callback on `NavigationContainer` now fires only when there are navigators rendered
-
-Previously, the `onReady` prop and `navigationRef.isReady()` worked slightly differently:
-
-- The `onReady` callback fired when `NavigationContainer` finishes mounting and deep links is resolved.
-- The `navigationRef.isReady()` method additionally checks if there are any navigators rendered - which may not be true if the user is rendering their navigators conditionally inside a `NavigationContainer`.
-
-This is important to know since if no navigator is rendered, we can't dispatch any navigation actions as there's no navigator to handle them. But the inconsistency between `onReady` and `navigationRef.isReady()` made it easy to cause issues and confusion.
-
-This changes `onReady` to work similar to `navigationRef.isReady()`. The `onReady` callback will now fire only when there are navigators rendered - reflecting the value of `navigationRef.isReady()`.
-
-This change is not breaking for most users, so you may not need to do anything.
-
-See [`onReady`](navigation-container.md#onready) for usage.
-
-#### The `independent` prop on `NavigationContainer` is removed in favor of `NavigationIndependentTree` component
-
-The `independent` prop on `NavigationContainer` was added to support rendering navigators in a separate tree from the rest of the app. This is useful for use cases such as miniapps.
-
-However, there are issues with this approach:
-
-- When building a miniapp, the responsibility of adding this prop was on the miniapp developer, which isn't ideal since forgetting it can cause problems.
-- A lot of beginners mistakenly added this prop and were confused why navigation wasn't working.
-
-So we've removed this prop instead of a `NavigationIndependentTree` component which you can use to wrap the navigation container:
-
-```diff lang=jsx
--
-- {/* ... */}
--
-+
-+
-+ {/* ... */}
-+
-+
-```
-
-This way, the responsibility no longer lies on the miniapp developer, but on the parent app. It's also harder for beginners to accidentally add this.
-
-See [Independent navigation containers](navigation-container.md#independent-navigation-containers) for usage.
-
-#### The `theme` prop now accepts a `fonts` property
-
-Previously, the `theme` prop on `NavigationContainer` accepted a `colors` property to customize the colors used by various UI elements from React Navigation. We have now added a `fonts` property to customize the fonts as well. If you are passing a custom theme in the `theme` prop, you'll need to update it to include the `fonts` property.
-
-```diff lang=js
-import { DefaultTheme } from '@react-navigation/native';
-
-const theme = {
- colors: {
- // ...
- },
-+ fonts: DefaultTheme.fonts,
-};
-```
-
-If you want to customize the fonts, see [the themes guide](themes.md) for more details.
-
-#### The navigation state is frozen in development mode
-
-The navigation state is now frozen in development mode to prevent accidental mutations. This includes the state object and all the nested objects such as `route` object etc. If you're mutating the navigation state directly, you may get an error like `Cannot assign to read only property 'key' of object`.
-
-Note that React Navigation relies on the immutability of the navigation state to detect changes and update the UI. Mutating the navigation state directly can cause issues and was never supported. So if you're mutating the navigation state directly, you'll need to use a different approach.
-
-### Changes to linking
-
-#### Encoding of params in path position is now more relaxed
-
-Previously, params were always URL encoded with `encodeURIComponent` regardless of their position (e.g. query position such as `?user=jane` or path position such as `/users/jane`) when generating a link for a screen (e.g. URL on the Web). This made it hard to use special characters in the params.
-
-Now, only the params in the query position are URL encoded. For the params in the path position, we only encode the characters that are not allowed in the path position.
-
-With this change, it's easier to use special characters such as `@` in the path. For example, to have a URL such as `profile/@username`, you can use the following in the linking config:
-
-```js
-const config = {
- prefixes: ['https://mysite.com'],
- config: {
- screens: {
- Profile: {
- path: 'profile/:username',
- parse: {
- username: (username) => username.replace(/^@/, ''),
- },
- stringify: {
- username: (username) => `@${username}`,
- },
- },
- },
- },
-};
-```
-
-See [Configuring links](configuring-links.md) for usage of the linking config.
-
-#### The `Link` component and `useLinkProps` hook now use screen names instead of paths
-
-Previously, the `Link` component and `useLinkProps` hook were designed to work with path strings via the `to` prop. But it had few issues:
-
-- The path strings are not type-safe, making it easy to cause typos and bugs after refactor
-- The API made navigating via screen name more inconvenient, even if that's the preferred approach
-
-Now, instead of the `to` prop that took a path string, they now accept `screen` and `params` props, as well as an optional `href` prop to use instead of the generated path:
-
-```diff lang=jsx
-- Go to Details
-+ Go to Details
-```
-
-or
-
-```diff lang=js
-- const props = useLinkProps({ to: '/details?foo=42' });
-+ const props = useLinkProps({ screen: 'Details', params: { foo: 42 } });
-```
-
-With this change, you'd now have full type-safety when using the `Link` component given that you have [configured the global type](typescript.md#specifying-default-types-for-usenavigation-link-ref-etc).
-
-See [`Link`](link.md) and [`useLinkProps`](use-link-props.md) for usage.
-
-#### The `useLinkBuilder` hooks now returns an object instead of a function
-
-Previously, the `useLinkBuilder` hooks returned a function to build a `href` for a screen - which is primarily useful for building custom navigators. Now, it returns an object with `buildHref` and `buildAction` methods:
-
-```js
-const { buildHref, buildAction } = useLinkBuilder();
-
-const href = buildHref('Details', { foo: 42 }); // '/details?foo=42'
-const action = buildAction('/details?foo=42'); // { type: 'NAVIGATE', payload: { name: 'Details', params: { foo: 42 } } }
-```
-
-The `buildHref` method acts the same as the previously returned function. The new `buildAction` method can be used to build a navigation action from a `href` string.
-
-Note that this hook is intended to be primarily used by custom navigators and not by end users. For end users, the `Link` component and `useLinkProps` are the recommended way to navigate.
-
-See [`useLinkBuilder`](use-link-builder.md) for usage.
-
-### Changes to navigators
-
-#### Screens pushed on top of modals are now shown as modals in the Stack and Native Stack navigators
-
-Previously, screens pushed on top of modals were shown as regular screens in the Stack and Native Stack navigators. This often caused glitchy animation on Stack Navigator and appeared behind the modal on Native Stack Navigator. This can be especially confusing if the user came to the screen from a deep link.
-
-Now, screens pushed on top of modals are automatically shown as modals to avoid these issues. This behavior can be disabled by explicitly setting the `presentation` option to `card`:
-
-```jsx
-
-```
-
-See [Stack Navigator](stack-navigator.md#presentation) and [Native Stack Navigator](native-stack-navigator.md#presentation) docs for usage.
-
-#### `headerBackTitleVisible` is removed in favor of `headerBackButtonDisplayMode` in Stack and Native Stack navigators
-
-Previously, `headerBackTitleVisible` could be used to control whether the back button title is shown in the header. It's now removed in favor of `headerBackButtonDisplayMode` which provides more flexibility.
-
-The previous behavior can be achieved by setting `headerBackButtonDisplayMode` to `default` and `minimal` for showing and hiding the back button title respectively:
-
-```diff lang=js
-
-```
-
-#### `animationEnabled` option is removed in favor of `animation` option in Stack Navigator
-
-Previously, `animationEnabled: false` was used to disable the animation for the screen transition in Stack Navigator.
-
-There's now a new `animation` prop to configure animations similar to the Native Stack. So you can now use `animation: 'none'` to disable the animation instead:
-
-```diff lang=js
-
-```
-
-See [Stack Navigator animation](stack-navigator.md#animations) for usage.
-
-#### `customAnimationOnGesture` is renamed to `animationMatchesGesture` in Native Stack Navigator
-
-The `customAnimationOnGesture` option in Native Stack Navigator is renamed to `animationMatchesGesture` to better reflect its purpose. If you are using `customAnimationOnGesture` in your project, you can rename it to `animationMatchesGesture`:
-
-```diff lang=js
--
-+
-```
-
-See [Native Stack Navigator](native-stack-navigator.md#animationmatchesgesture) for usage.
-
-#### `statusBarColor` is renamed to `statusBarBackgroundColor` in Native Stack Navigator
-
-The `statusBarColor` option in Native Stack Navigator is renamed to `statusBarBackgroundColor` to better reflect its purpose. If you are using `statusBarColor` in your project, you can rename it to `statusBarBackgroundColor`:
-
-```diff lang=js
--
-+
-```
-
-See [Native Stack Navigator](native-stack-navigator.md#statusbarbackgroundcolor) for usage.
-
-#### Native Stack now requires `react-native-screens` 4
-
-`@react-navigation/native-stack` now requires `react-native-screens` 4 and will break when using an earlier version. If you are using Native Stack Navigator in your project, make sure to upgrade `react-native-screens` to version 4.
-
-See [Native Stack Navigator](native-stack-navigator.md) for usage.
-
-#### Material Top Tab Navigator no longer requires installing `react-native-tab-view`
-
-Previously, `@react-navigation/material-top-tabs` required installing `react-native-tab-view` as a dependency in the project. We have now moved this package to the React Navigation monorepo and able to coordinate the releases together, so it's no longer necessary to install it separately.
-
-If you use `@react-navigation/material-top-tabs` and don't use `react-native-tab-view` anywhere else in your project, you can remove it from your dependencies after upgrading.
-
-If you need to enforce a specific version of `react-native-tab-view` for some reason, we recommend using [Yarn resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) or [npm overrides](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides) to do so.
-
-See [Material Top Tab Navigator](material-top-tab-navigator.md) for usage.
-
-#### The `unmountOnBlur` option is removed in favor of `popToTopOnBlur` in Bottom Tab Navigator and Drawer Navigator
-
-In many cases, the desired behavior is to return to the first screen of the stack nested in a tab or drawer navigator after it's unfocused. Previously, the `unmountOnBlur` option was used to achieve this behavior. However, it had some issues:
-
-- It destroyed the local state of the screen in the stack.
-- It was slow to remount the nested navigator on tab navigation.
-
-The `popToTopOnBlur` option provides an alternative approach - it pops the screens on a nested stack to go back to the first screen in the stack and doesn't have the above issues.
-
-See [Bottom Tab Navigator](bottom-tab-navigator.md#poptotoponblur) and [Drawer Navigator](drawer-navigator.md#poptotoponblur) docs for usage.
-
-It's still possible to achieve the old behavior of `unmountOnBlur` by using the [`useIsFocused`](use-is-focused.md) hook in the screen:
-
-```js
-const isFocused = useIsFocused();
-
-if (!isFocused) {
- return null;
-}
-```
-
-This could also be combined with the new [layout props](#new-layout-props) to specify it at the screen configuration level to make the migration easier.
-
-To achieve this, define a component that uses the `useIsFocused` hook to conditionally render its children:
-
-```js
-function UnmountOnBlur({ children }) {
- const isFocused = useIsFocused();
-
- if (!isFocused) {
- return null;
- }
-
- return children;
-}
-```
-
-Then use the component in `layout` prop of the screen:
-
-```diff lang=js
- {children} }
- options={{
-- unmountOnBlur: true,
- }}
-/>
-```
-
-Or `screenLayout` prop of the navigator:
-
-```diff lang=js
- {children} }
- screenOptions={{
-- unmountOnBlur: true,
- }}
->
-```
-
-#### The `tabBarTestID` option is renamed to `tabBarButtonTestID` in Bottom Tab Navigator and Material Top Tab Navigator
-
-The `tabBarTestID` option in `@react-navigation/bottom-tabs` and `@react-navigation/material-top-tabs` is renamed to `tabBarButtonTestID` to better reflect its purpose. If you are using `tabBarTestID` in your project, you can rename it to `tabBarButtonTestID`:
-
-```diff lang=js
--
-+
-```
-
-See [Bottom Tab Navigator](bottom-tab-navigator.md#tabbarbuttontestid) and [Material Top Tab Navigator](material-top-tab-navigator.md#tabbarbuttontestid) docs for usage.
-
-#### The `sceneContainerStyle` prop and option are removed from Bottom Tab Navigator, Material Top Tab Navigator and Drawer Navigator in favor of `sceneStyle`
-
-Previously, the Bottom Tab Navigator and Material Top Tab Navigator accepted a `sceneContainerStyle` prop to style the container of the scene. This was inflexible as it didn't allow different styles for different screens. Now, the `sceneStyle` option is added to these navigators to style individual screens.
-
-Similarly, the `sceneContainerStyle` option in Drawer Navigator is renamed to `sceneStyle` for consistency.
-
-If you are using `sceneContainerStyle` prop, you can pass `sceneStyle` in `screenOptions` instead to keep the same behavior:
-
-```diff lang=js
--
-+
-```
-
-#### Drawer Navigator now requires Reanimated 2 or 3 on native platforms
-
-Previously, `@react-navigation/drawer` supported both Reanimated 1 and Reanimated 2 APIs with the `useLegacyImplementation` option. This is now no longer supported and the `useLegacyImplementation` option is removed.
-
-If you are using Reanimated 1 in your project, you'll need to upgrade to Reanimated 2 or 3 to use `@react-navigation/drawer`.
-
-If you're using Drawer Navigator on the Web, it'll now use CSS transitions instead of Reanimated for a smaller bundle size.
-
-See [Drawer Navigator](drawer-navigator.md) for usage.
-
-### Changes to elements
-
-#### `labelVisible` is removed in favor of `displayMode` in `headerLeft` and `HeaderBackButton` elements
-
-Previously, `labelVisible` could be used to control whether the back button title is shown in the header. It's now removed in favor of `displayMode` which provides more flexibility.
-
-The new possible values are:
-
-- `default`: Displays one of the following depending on the available space: previous screen's title, generic title (e.g. 'Back') or no title (only icon).
-- `generic`: Displays one of the following depending on the available space: generic title (e.g. 'Back') or no title (only icon). iOS >= 14 only, falls back to "default" on older iOS versions.
-- `minimal`: Always displays only the icon without a title.
-
-The previous behavior can be achieved by setting `displayMode` to `default` or `generic` for showing and `minimal` for hiding the back button title respectively:
-
-```diff lang=js
-
-```
-
-### Deprecations and removals
-
-#### Material Bottom Tab Navigator now lives in `react-native-paper` package
-
-The `@react-navigation/material-bottom-tabs` package provided React Navigation integration for `react-native-paper`'s `BottomNavigation` component. To make it easier to keep it updated with the changes in `react-native-paper`, we have now moved it to the `react-native-paper` package.
-
-If you are using `@react-navigation/material-bottom-tabs` in your project, you can remove it from your dependencies and change the imports to `react-native-paper/react-navigation` instead:
-
-```diff lang=js
-- import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
-+ import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation';
-```
-
-See [Material Bottom Tab Navigator](https://callstack.github.io/react-native-paper/docs/guides/bottom-navigation/) for usage.
-
-Alternatively, you can use the [`BottomNavigation.Bar`](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar) component as a custom tab bar with `@react-navigation/bottom-tabs`.
-
-For any issues related to the Material Bottom Tab Navigator or `BottomNavigation.Bar`, please open them in the [react-native-paper repository](https://github.com/callstack/react-native-paper) instead of the React Navigation repository.
-
-#### The flipper devtools plugin is now removed
-
-Previously, we added a Flipper plugin for React Navigation to make debugging navigation easier. However, it has added significant maintenance overhead for us. The Flipper team hasn't been focused on React Native recently, so the overall experience of using Flipper with React Native has been poor.
-
-> Currently, the Flipper team has been focused on native developer experience, so we are going back to the drawing board. We have created a new pillar within our team focused on Developer Experience. We are currently investigating improved Chrome Debugger protocol support from the Hermes team as well as migrating the debugging experience from Flipper to Chrome DevTools so we can deliver a debugging experience that meets our standard.
->
-> [react-native-community/discussions-and-proposals#546 (comment)](https://github.com/react-native-community/discussions-and-proposals/discussions/546#discussioncomment-4178951)
-
-Since the React Native team migrating away from Flipper, it doesn't make much sense for us to spend additional resources to keep supporting it. So we've removed the Flipper plugin from `@react-navigation/devtools`.
-
-Alternatively, you can use the following developer tools:
-
-- [Logger](devtools.md#uselogger)
-- [Integration for Redux DevTools Extension](devtools.md#usereduxdevtoolsextension)
-- [Devtools plugin for Expo](https://docs.expo.dev/debugging/devtools-plugins/#react-navigation) if you are using [Expo](https://expo.dev).
-
-#### Various deprecated APIs are removed
-
-We have removed all of the previously deprecated APIs. These APIs were deprecated in React Navigation 6 and showed a warning when used. So make sure that you have addressed all the warnings before upgrading.
-
-
-Full list of removed APIs
-
-- `@react-navigation/stack`
- - Removed `mode` prop - use `presentation` option instead
- - Removed `headerMode` prop - use `headerMode` and `headerShown` options instead
- - Removed `keyboardHandlingEnabled` prop - use `keyboardHandlingEnabled` option instead
-- `@react-navigation/drawer`
- - Removed `openByDefault` prop - use `defaultStatus` prop instead
- - Removed `lazy` prop - use `lazy` option instead
- - Removed `drawerContentOptions` prop which contained following options:
- - `drawerPosition` - use `drawerPosition` option instead
- - `drawerType` - use `drawerType` option instead
- - `edgeWidth` - use `swipeEdgeWidth` option instead
- - `hideStatusBar` - use `drawerHideStatusBarOnOpen` option instead
- - `keyboardDismissMode` - use `keyboardDismissMode` option instead
- - `minSwipeDistance` - use `swipeMinDistance` option instead
- - `overlayColor` - use `overlayColor` option instead
- - `statusBarAnimation` - use `drawerStatusBarAnimation` option instead
- - `gestureHandlerProps` - use `configureGestureHandler` option instead
-- `@react-navigation/bottom-tabs`
- - Removed `lazy` prop - use `lazy` option instead
- - Removed `tabBarOptions` prop which contained following options:
- - `keyboardHidesTabBar` - use `tabBarHideOnKeyboard` option instead
- - `activeTintColor` - use `tabBarActiveTintColor` option instead
- - `inactiveTintColor` - use `tabBarInactiveTintColor` option instead
- - `activeBackgroundColor` - use `tabBarActiveBackgroundColor` option instead
- - `inactiveBackgroundColor` - use `tabBarInactiveBackgroundColor` option instead
- - `allowFontScaling` - use `tabBarAllowFontScaling` option instead
- - `showLabel` - use `tabBarShowLabel` option instead
- - `labelStyle` - use `tabBarLabelStyle` option instead
- - `iconStyle` - use `tabBarIconStyle` option instead
- - `tabStyle` - use `tabBarItemStyle` option instead
- - `labelPosition` and `adapative` - use `tabBarLabelPosition` option instead
- - `tabBarVisible` - use `display: 'none'` `tabBarStyle` option instead
-- `@react-navigation/material-top-tabs`
- - Removed `swipeEnabled` prop - use `swipeEnabled` option instead
- - Removed `lazy` prop - use `lazy` option instead
- - Removed `lazyPlaceholder` prop - use `lazyPlaceholder` option instead
- - Removed `lazyPreloadDistance` prop - use `lazyPreloadDistance` option instead
- - Removed `tabBarOptions` prop which contained following options: - `renderBadge` - use `tabBarBadge` option instead - `renderIndicator` - use `tabBarIndicator` option instead - `activeTintColor` - use `tabBarActiveTintColor` option instead - `inactiveTintColor` - use `tabBarInactiveTintColor` option instead - `pressColor` - use `tabBarPressColor` option instead - `pressOpacity` - use `tabBarPressOpacity` option instead - `showLabel` - use `tabBarShowLabel` option instead - `showIcon` - use `tabBarShowIcon` option instead - `allowFontScaling` - use `tabBarAllowFontScaling` option instead - `bounces` - use `tabBarBounces` option instead - `scrollEnabled` - use `tabBarScrollEnabled` option instead - `iconStyle` - use `tabBarIconStyle` option instead - `labelStyle` - use `tabBarLabelStyle` option instead - `tabStyle` - use `tabBarItemStyle` option instead - `indicatorStyle` - use `tabBarIndicatorStyle` option instead - `indicatorContainerStyle` - use `tabBarIndicatorContainerStyle` option instead - `contentContainerStyle` - use `tabBarContentContainerStyle` option instead - `style` - use `tabBarStyle` option instead
-
-
-
-### Miscellaneous
-
-#### Various UI elements now follow Material Design 3 guidelines
-
-Previously, the UI elements in React Navigation such as the header on platforms other than iOS, drawer, material top tabs etc. were following the Material Design 2 guidelines. We have now updated them to follow the Material Design 3 guidelines.
-
-#### React Native Tab View now has a new API to specify various options
-
-The API for the `TabView` and `TabBar` component in `react-native-tab-view` has been revamped.
-
-Some of props accepted by the `TabBar` have now been replaced with `commonOptions` and `options` props on `TabView`:
-
-- `getLabelText` -> `labelText`
-- `getAccessible` -> `accessible`
-- `getAccessibilityLabel` -> `accessibilityLabel`
-- `getTestID` -> `testID`
-- `renderIcon` -> `icon`
-- `renderLabel` -> `label`
-- `renderBadge` -> `badge`
-- `labelStyle`
-- `sceneContainerStyle` -> `sceneStyle`
-
-To keep the same behavior when updating your existing code, move these props to `commonOptions` prop on `TabView`:
-
-```diff lang=js
- (
--
-+
- )}
-+ commonOptions={{
-+ label: renderLabel,
-+ labelStyle,
-+ }}
-/>
-```
-
-The options can also be customized individually for each tab by passing an object to the `options` prop with the `route.key` as the key and the options as the value:
-
-```js
- (
-
- ),
- }}
- options={{
- albums: {
- labelText: 'Albums',
- },
- profile: {
- labelText: 'Profile',
- },
- }}
-/>
-```
-
-When using a custom tab bar, it will receive the `options` in the arguments.
-
-The new API will make it easier for us to improve re-rendering performance of the tab bar items in the library.
-
-See [React Native Tab View](tab-view.md#options) for usage.
-
-#### Custom navigators now require more type information
-
-Custom navigators now require more type information to work correctly so that we can provide better type-checking and autocompletion in TypeScript when using the navigator.
-
-```diff lang=js
-- export const createMyNavigator = createNavigatorFactory<
-- MyNavigationState,
-- MyNavigationOptions,
-- MyNavigationEventMap,
-- typeof MyNavigator
-- >(MyNavigator);
-+ export function createMyNavigator<
-+ const ParamList extends ParamListBase,
-+ const NavigatorID extends string | undefined = undefined,
-+ const TypeBag extends NavigatorTypeBagBase = {
-+ ParamList: ParamList;
-+ NavigatorID: NavigatorID;
-+ State: TabNavigationState;
-+ ScreenOptions: TabNavigationOptions;
-+ EventMap: TabNavigationEventMap;
-+ NavigationList: {
-+ [RouteName in keyof ParamList]: TabNavigationProp<
-+ ParamList,
-+ RouteName,
-+ NavigatorID
-+ >;
-+ };
-+ Navigator: typeof TabNavigator;
-+ },
-+ const Config extends StaticConfig = StaticConfig,
-+ >(config?: Config): TypedNavigator {
-+ return createNavigatorFactory(MyNavigator)(config);
-+ }
-```
-
-See [Custom navigators](custom-navigators.md) for usage.
-
-#### Packages now use ESM and package exports
-
-All the packages in React Navigation now use ESM exports. While it shouldn't affect most users, there are some changes to be aware of:
-
-- If you are importing internal files from the packages, they might now be restricted by your bundler and it won't be possible to import them directly. You should use the public API instead.
-- If you're patching the packages using `patch-package`, `yarn patch` etc., you'll need to patch the built files under `lib/` folders instead of the source files under `src/` as the source files are no longer exported.
-- If you're using TypeScript with the `module` or `moduleResolution` option, it maybe necessary to set `moduleResolution` to `bundler` to match [Metro's resolution behavior](https://reactnative.dev/blog/2023/06/21/package-exports-support#enabling-package-exports-beta).
-- If you're using Webpack for bundling code using React Navigation, it maybe necessary to set [`resolve.fullySpecified`](https://webpack.js.org/configuration/module/#resolvefullyspecified) to `false` for bundling to work.
-
-## New features
-
-### Static configuration API
-
-React Navigation 5 introduced a dynamic API to support more flexible use cases. With React Navigation 7, we are re-introducing a static configuration API:
-
-```js
-import { createNativeStackNavigator } from '@react-navigation/native-stack';
-
-const MyStack = createNativeStackNavigator({
- screens: {
- Home: {
- screen: HomeScreen,
- options: {
- title: 'My App',
- },
- },
- Details: {
- screen: DetailsScreen,
- linking: 'details/:id',
- },
- },
-});
-```
-
-The static configuration API provides the following benefits:
-
-- **Simpler type-checking with TypeScript**: It's not necessary to specify screens and their params separately. See [Type checking with TypeScript](typescript.md?config=static) for more details.
-- **Easier deep linking setup**: Paths can be generated automatically. Linking configuration can be defined next to the screen for explicit configuration. See [Configuring links](configuring-links.md?config=static) for more details.
-
-It's also possible to mix the static and dynamic configuration APIs. For example, you can use the static configuration API for the top-level navigators and the dynamic configuration API for the nested navigators where you need more flexibility.
-
-:::note
-
-The static configuration API doesn't replace the dynamic configuration API. Both APIs are equally supported and you can choose the one that fits your use case better.
-
-:::
-
-You can see examples for both the static and dynamic configuration APIs in the documentation by selecting the appropriate tab in the examples.
-
-Go to ["Hello React Navigation"](hello-react-navigation.md?config=static) to start writing some code with the static API.
-
-### Improved TypeScript support
-
-Previously, the `navigation` object received in `options` and `listeners` callbacks were typed as `any` and required manual type annotation. Now, the `navigation` object has a more accurate type based on the navigator it's used in, and the type annotation is no longer required.
-
-We also export a new `XOptionsArgs` (where `X` is the navigator name, e.g. `StackOptionsArgs`, `BottomTabOptionsArgs` etc.) type which can be used to type the arguments of the `options` callback. This can be useful if you want to define the options callback separately.
-
-```ts
-const options = ({
- route,
-}: StackOptionsArgs) => {
- return {
- title: route.params.title,
- };
-};
-```
-
-### Improved RTL support
-
-Previously, various UI elements used the `I18nManager` API to determine the writing direction. However, this API doesn't work well on the Web as the writing direction can be different for a specific subtree and hence can't be determined globally.
-
-The `NavigationContainer` now accepts a `direction` prop to specify the direction of the layout instead of relying on the `I18nManager` API. It also exposes this value via `useLocale` hook for use in your own components.
-
-See the [navigation container docs](navigation-container.md#direction) for usage.
-
-### The `options` callback gets `theme`
-
-The `options` callback now receives the `theme` object to allow customizing the UI elements specified in the options:
-
-```jsx
- ({
- headerRight: () => (
- {}}
- color={theme.colors.primary}
- />
- ),
- })}
-/>
-```
-
-See [Screen options](screen-options.md) for usage.
-
-### Top-level `path` in linking config
-
-The linking configuration now supports a top-level `path` configuration to define the base path for all the screens in the navigator:
-
-```js
-const linking = {
- prefixes: ['https://mysite.com'],
- config: {
- // highlight-next-line
- path: 'app',
- screens: {
- Home: 'home',
- Details: 'details/:id',
- },
- },
-};
-```
-
-This can be useful if your app lives under a subpath on the web. For example, if your app lives under `https://mysite.com/app`, you can define the `path` as `app` and the `Details` screen will be accessible at `https://mysite.com/app/details/42`.
-
-See [Configuring links](configuring-links.md#apps-under-subpaths) for usage.
-
-### Improved Web integration
-
-More built-in UI elements that trigger navigation now render `a` tags on the Web for better accessibility and SEO. This includes:
-
-- Back button in the header
-- The tab buttons in material top tab navigator
-
-UI elements such as the bottom tab bar and drawer items already rendered `a` tags on the Web.
-
-### New `usePreventRemove` hook
-
-Previously, the only way to prevent a screen from being removed from the stack was to use the `beforeRemove` event. This didn't work well with the Native Stack Navigator.
-
-The new `usePreventRemove` hook is an alternative to `beforeRemove` that works with the Native Stack Navigator.
-
-See [`usePreventRemove`](use-prevent-remove.md) for usage.
-
-### New `layout` props
-
-#### For navigators
-
-Navigators now support a `layout` prop. It can be useful for augmenting the navigators with additional UI with a wrapper. The difference from adding a regular wrapper is that the code in `layout` callback has access to the navigator's state, options etc.:
-
-```jsx
- (
-
-
- {children}
-
- )}
- // highlight-end
->
- {/* ... */}
-
-```
-
-See [Navigator layout](navigator.md#layout) for usage.
-
-#### For screens and groups
-
-The `layout` prop makes it easier to provide things such as a global error boundary and suspense fallback for a group of screens without having to manually add HOCs for every screen separately.
-
-It can be used for a single screen with [`layout`](screen.md#layout):
-
-```jsx
- (
-
-
- Loading…
-
- }
- >
- {children}
-
-
- )}
- // highlight-end
-/>
-```
-
-Or with a [group](group.md#screen-layout) or [navigator](navigator.md#screen-layout) with `screenLayout`:
-
-```jsx
- (
-
-
- Loading…
-
- }
- >
- {children}
-
-
- )}
->
- // highlight-end
- {/* screens */}
-
-```
-
-### Preloading screens
-
-All built-in navigators now support preloading screens prior to navigating to them. This can be useful to improve the perceived performance of the app by preloading the screens that the user is likely to navigate to next. Preloading a screen will render it off-screen and execute its side-effects such as data fetching.
-
-To preload a screen, you can use the `preload` method on the navigation object:
-
-```js
-navigation.preload('Details', { id: 42 });
-```
-
-See [`preload`](navigation-object.md#preload) for usage.
-
-### Improvements to navigators
-
-#### Bottom Tab Navigator can now show tabs on the side and top
-
-The `@react-navigation/bottom-tabs` package now supports showing tabs on the side. This will make it easier to build responsive UIs for where you want to show tabs on the bottom on smaller screens and switch to a sidebar on larger screens.
-
-Similarly, showing tabs on the top is also supported which can be useful for Android TV or Apple TV apps.
-
-You can use the `tabBarPosition` option to customize the position of the tabs:
-
-```jsx
-
- {/* ... */}
-
-```
-
-See [Bottom Tab Navigator options](bottom-tab-navigator.md#tabbarposition) for usage.
-
-#### Bottom Tab Navigator now supports animations
-
-The `@react-navigation/bottom-tabs` package now supports animations. This was one of the most requested features on our Canny board: [TabNavigator Custom Transition](https://react-navigation.canny.io/feature-requests/p/tabnavigator-custom-transition).
-
-You can use the `animation` option to customize the animations for the tab transitions:
-
-```jsx
-
- {/* ... */}
-
-```
-
-See [Bottom Tab Navigator animation](bottom-tab-navigator.md#animations) for usage.
-
-#### Stack Navigator now supports an `animation` option
-
-The `@react-navigation/stack` package now supports an `animation` option to customize the animations for the screen transitions:
-
-```jsx
-
- {/* ... */}
-
-```
-
-The `animation` option is an alternative to the `TransitionPresets` API, and is intended to make migrating between JS stack and native stack navigators easier.
-
-See [Stack Navigator animation](stack-navigator.md#animations) for usage.
-
-#### Native Stack Navigator now exports a `useAnimatedHeaderHeight` hook
-
-The `@react-navigation/native-stack` package now exports a `useAnimatedHeaderHeight` hook. It can be used to animate content based on the header height changes - such as when the large title shrinks to a small title on iOS:
-
-```jsx
-const headerHeight = useAnimatedHeaderHeight();
-
-return (
-
- {/* ... */}
-
-);
-```
-
-#### All navigators with headers now support `headerSearchBarOptions`
-
-The `Header` component from `@react-navigation/elements` now supports a `headerSearchBarOptions` prop. This means all navigators that use the `Header` component now support a search bar in the header as well on all platforms. Previously, this was only available in the Native Stack Navigator on iOS and Android.
-
-```js
-React.useLayoutEffect(() => {
- navigation.setOptions({
- headerSearchBarOptions: {
- placeholder: 'Search',
- onChangeText: (text) => {
- // Do something
- },
- },
- });
-}, [navigation]);
-```
-
-See [`headerSearchBarOptions`](elements.md#headersearchbaroptions) for usage.
-
-### New components in elements library
-
-The `@react-navigation/elements` package now includes new components that can be used in your app:
-
-#### `Button`
-
-The `Button` component has built-in support for navigating to screens, and renders an anchor tag on the Web when used for navigation:
-
-```jsx
-
- View Jane's Profile
-
-```
-
-It can also be used as a regular button:
-
-```jsx
- {
- /* do something */
- }}
->
- Do something
-
-```
-
-The button follows the [Material Design 3 guidelines](https://m3.material.io/components/buttons/overview).
-
-See [`Button`](elements.md#button) for usage.
-
-#### `HeaderButton`
-
-The `HeaderButton` component can be used to render buttons in the header with appropriate styling:
-
-```js
-headerRight: ({ tintColor }) => (
- {
- /* do something */
- }}
- >
-
-
-),
-```
-
-See [`HeaderButton`](elements.md#headerbutton) for usage.
-
-#### `Label`
-
-The `Label` component can be used to render label text, such as the label in a tab bar button:
-
-```jsx
-Home
-```
-
-See [`Label`](elements.md#label) for usage.
-
-### `react-native-drawer-layout` package
-
-The drawer implementation used in `@react-navigation/drawer` is now available as a standalone package called `react-native-drawer-layout`. This makes it easier to use the drawer implementation even if you're not using React Navigation, or if you want to use it without a navigator.
-
-You can install it with:
-
-```bash npm2yarn
-npm install react-native-drawer-layout
-```
-
-See [`react-native-drawer-layout`](drawer-layout.md) for usage.
-
-### `useLogger` devtool
-
-The `@react-navigation/devtools` package now exports a `useLogger` hook. It can be used to log navigation actions to the console:
-
-See [`useLogger`](devtools.md#uselogger) for usage.
diff --git a/versioned_docs/version-8.x/upgrading-from-7.x.md b/versioned_docs/version-8.x/upgrading-from-7.x.md
new file mode 100755
index 00000000000..13fa1260249
--- /dev/null
+++ b/versioned_docs/version-8.x/upgrading-from-7.x.md
@@ -0,0 +1,676 @@
+---
+id: upgrading-from-7.x
+title: Upgrading from 7.x
+sidebar_label: Upgrading from 7.x
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::warning
+
+React Navigation 8 is still in pre-release stage. The API may still change before the stable release. The upgrade guide will be updated accordingly when we release the stable version.
+
+:::
+
+This guides lists all the breaking changes and new features in React Navigation 8 that you need to be aware of when upgrading from React Navigation 7.
+
+## Dependency changes
+
+The minimum required version of React Native, Expo, and TypeScript have been bumped:
+
+- `react-native` >= 0.81
+- `expo` >= 54 (if you use [Expo Go](https://expo.dev/go))
+- `typescript` >= 5.9.2 (if you use TypeScript)
+
+The minimum required version of various peer dependencies have also been bumped:
+
+- `react-native-screens` >= 3.22.0
+- `react-native-safe-area-context` >= 5.5.0
+- `react-native-reanimated` >= 4.0.0
+- `react-native-web` >= 0.21.0
+
+Previously, many navigators worked without `react-native-screens`, but now it's required for all navigators.
+
+Additionally, React Navigation now uses [`@callstack/liquid-glass`](https://github.com/callstack/liquid-glass) to implement liquid glass effect on iOS 26.
+
+## Breaking changes
+
+### Dropping support for old architecture
+
+React Navigation 8 no longer supports the old architecture of React Native. The old architecture has been frozen since React Native 0.80 and will be removed in React Native 0.82.
+
+So if you're still on the old architecture, you'll need to upgrade to the new architecture in order to use React Navigation 8.
+
+### Changes to TypeScript setup
+
+We introduced a static API in React Navigation 7. However, some of the TypeScript types were not inferred and required manual annotations. In React Navigation 8, we reworked the TypeScript types to solve many of these issues.
+
+#### The root type now uses navigator type instead of param list
+
+Previously the types for the root navigator were specified using `declare global` and `RootParamList`. Now, they can be specified with module augmentation of `@react-navigation/core` and use the navigator's type instead a param list:
+
+```diff lang=ts
+- type RootStackParamList = StaticParamList;
+-
+- declare global {
+- namespace ReactNavigation {
+- interface RootParamList extends RootStackParamList {}
+- }
+- }
++ type RootStackType = typeof RootStack;
++
++ declare module '@react-navigation/core' {
++ interface RootNavigator extends RootStackType {}
++ }
+```
+
+Using module augmentation is shorter, and avoids namespace usage - which ESLint may complain about in some configurations.
+
+Using the navigator's type instead of a param list allows to infer the type of navigators - primarily in case of static configuration.
+
+#### Common hooks no longer accept generics
+
+Previously hooks such as `useNavigation`, `useRoute` and `useNavigationState` accepted a generic to override the default types. This is not type-safe as we cannot verify that the provided type matches the actual navigators, and we recommended minimizing such usage.
+
+In React Navigation 8, we reworked the types to automatically determine the correct type [based on the name of the screen](#common-hooks-now-accept-name-of-the-screen) when using static config:
+
+```diff lang=ts
+- const navigation = useNavigation>();
++ const navigation = useNavigation('Profile');
+```
+
+If you're using dynamic configuration, unfortunately we cannot currently infer the types automatically. So it still requires manual annotation. However, now you need to use `as` instead of generics to make it clearer that this is unsafe:
+
+```diff lang=ts
+- const navigation = useNavigation>();
++ const navigation = useNavigation() as StackNavigationProp;
+```
+
+The `useRoute` type has been updated in the same way:
+
+```diff lang=ts
+- const route = useRoute>();
++ const route = useRoute('Profile');
+```
+
+And if you're using dynamic configuration:
+
+```diff lang=ts
+- const route = useRoute>();
++ const route = useRoute() as RouteProp;
+```
+
+Similarly, the `useNavigationState` type has been updated to accept the name of the screen in addition to the selector:
+
+```diff lang=ts
+- const focusedRouteName = useNavigationState((state) => state.routes[state.index].name);
++ const focusedRouteName = useNavigationState('Settings', (state) => state.routes[state.index].name);
+```
+
+If you're using dynamic configuration, you can use `as`:
+
+```diff lang=ts
+- const focusedRouteName = useNavigationState((state) => state.routes[state.index].name);
++ const focusedRouteName = useNavigationState((state) => state.routes[state.index].name as keyof RootStackParamList);
+```
+
+#### New `createXScreen` API for creating screen config
+
+One of the limitations of the static config API is that the type of `route` object can't be inferred in screen callback, listeners callback etc. This made it difficult to use route params in these callbacks.
+
+To address this, we added a new `createXScreen` API for each navigator to create screen config with proper types:
+
+```diff lang=js
+const Stack = createStackNavigator({
+ screens: {
+- Profile: {
+- screen: ProfileScreen,
+- options: ({ route }) => {
+- const userId = route.params.userId; // Don't know the type of route params
+-
+- return { title: `User ${userId}` };
+- },
+- },
++ Profile: createStackScreen({
++ screen: ProfileScreen,
++ options: ({ route }) => {
++ const userId = route.params.userId; // Now correctly inferred
++
++ return { title: `User ${userId}` };
++ },
++ });
+ }
+});
+```
+
+When using the `createXScreen` API, the type of params are automatically inferred based on the type annotation for the component specified in `screen` (e.g. `(props: StaticScreenProps)`) and the path pattern specified in the linking config (e.g. `linking: 'profile/:userId'`).
+
+Each navigator exports its own helper function, e.g. `createNativeStackScreen` for Native Stack Navigator, `createBottomTabScreen` for Bottom Tab Navigator, `createDrawerScreen` for Drawer Navigator etc.
+
+See [Static configuration docs](static-configuration.md#createxscreen) for more details.
+
+#### Custom navigators now require overloads for types
+
+To work with the reworked TypeScript types, custom navigators now need to provide overloads for static and dynamic configuration APIs, and an additional API to create screen config.
+
+```diff lang=ts
+- export function createMyNavigator<
+- const ParamList extends ParamListBase,
+- const NavigatorID extends string | undefined = string | undefined,
+- const TypeBag extends NavigatorTypeBagBase = {
+- ParamList: ParamList;
+- NavigatorID: NavigatorID;
+- State: TabNavigationState;
+- ScreenOptions: MyNavigationOptions;
+- EventMap: MyNavigationEventMap;
+- NavigationList: {
+- [RouteName in keyof ParamList]: MyNavigationProp<
+- ParamList,
+- RouteName,
+- NavigatorID
+- >;
+- };
+- Navigator: typeof MyNavigator;
+- },
+- const Config extends StaticConfig = StaticConfig,
+- >(config?: Config): TypedNavigator {
+- return createNavigatorFactory(MyNavigator)(config);
+- }
++ type MyTypeBag = {
++ ParamList: ParamList;
++ State: TabNavigationState;
++ ScreenOptions: MyNavigationOptions;
++ EventMap: MyNavigationEventMap;
++ NavigationList: {
++ [RouteName in keyof ParamList]: MyNavigationProp<
++ ParamList,
++ RouteName
++ >;
++ };
++ Navigator: typeof MyNavigator;
++ };
++
++ export function createMyNavigator<
++ const ParamList extends ParamListBase,
++ >(): TypedNavigator, undefined>;
++ export function createMyNavigator<
++ const Config extends StaticConfig>,
++ >(
++ config: Config
++ ): TypedNavigator<
++ MyTypeBag>,
++ Config
++ >;
++ export function createMyNavigator(config?: unknown) {
++ return createNavigatorFactory(MyNavigator)(config);
++ }
+
++ export function createMyScreen<
++ const Linking extends StaticScreenConfigLinking,
++ const Screen extends StaticScreenConfigScreen,
++ >(
++ config: StaticScreenConfigInput<
++ Linking,
++ Screen,
++ TabNavigationState,
++ MyNavigationOptions,
++ MyNavigationEventMap,
++ MyNavigationProp
++ >
++ ): StaticScreenConfigResult<
++ Linking,
++ Screen,
++ TabNavigationState,
++ MyNavigationOptions,
++ MyNavigationEventMap,
++ MyNavigationProp
++ > {
++ // @ts-expect-error: there is some issue with the generic inference here
++ return config;
++ }
+```
+
+See [Custom navigators](custom-navigators.md) for more details.
+
+### Changes to navigators
+
+#### Native Bottom Tabs are now default
+
+Previously, the Bottom Tab Navigator used a JavaScript-based implementation and a native implementation was available under `@react-navigation/bottom-tabs/unstable`. Native bottom tabs are not used by default on iOS and Android. This allows us to match the new native design such as liquid glass effect on iOS 26.
+
+The `@react-navigation/bottom-tabs/unstable` entry point has been removed.
+
+To keep the previous behavior with JavaScript-based tabs, you can pass `implementation: 'custom'` to the navigator:
+
+
+
+
+```diff lang=js
+createBottomTabNavigator({
++ implementation: 'custom',
+ // ...
+});
+```
+
+
+
+
+```diff lang=js
+
+```
+
+
+
+
+As part of this change, some of the options have changed to work with native tabs:
+
+- `tabBarShowLabel` is replaced with `tabBarLabelVisibilityMode` which accepts:
+ - `"auto"` (default)
+ - `"selected"`
+ - `"labeled"` - same as `tabBarShowLabel: true`
+ - `"unlabeled"` - same as `tabBarShowLabel: false`
+- `tabBarLabel` now only accepts a `string`
+- `tabBarIcon` now accepts an function that returns an icon object
+
+The following props have been removed:
+
+- `safeAreaInsets` from the navigator props
+- `insets` from the bottom tab bar props
+- `layout` from the bottom tab bar props
+
+See the [Bottom Tab Navigator docs](bottom-tab-navigator.md) for all the available options.
+
+#### Navigators no longer accept an `id` prop
+
+Previously, navigators accepted an `id` prop to identify them - which was used with `navigation.getParent(id)` to get a parent navigator by id. However, there were a couple of issues with this approach:
+
+- It wasn't well integrated with TypeScript types, and required manual annotations.
+- The navigation object is specific to a screen, so using the navigator's id was inconsistent.
+- It was used for a very specific use case, so it added unnecessary complexity.
+
+In React Navigation 8, we removed the `id` prop from navigators. Instead, you can use the screen's name to get a parent navigator:
+
+```diff lang=js
+- const parent = navigation.getParent('some-id');
++ const parent = navigation.getParent('SomeScreenName');
+```
+
+In this case, 'SomeScreenName' refers to the name of a parent screen that's used in the navigator.
+
+See [navigation object docs](navigation-object.md#getparent) for more details.
+
+#### `setParams` no longer pushes to history in tab and drawer navigators when `backBehavior` is set to `fullHistory`
+
+Previously, when using `setParams` in tab and drawer navigators with `backBehavior` set to `fullHistory`, it would push a new entry to the history stack.
+
+In React Navigation 8, we [added a new `pushParams` action](#new-entry-can-be-added-to-history-stack-with-pushparams-action) that achieves this behavior. So `setParams` now only updates the params without affecting the history stack.
+
+```diff lang=js
+- navigation.setParams({ filter: 'new' });
++ navigation.pushParams({ filter: 'new' });
+```
+
+This way you have more control over how params are updated in tab and drawer navigators.
+
+See [`setParams` action docs](navigation-actions.md#setparams) for more details.
+
+#### Navigators no longer use `InteractionManager`
+
+Previously, various navigators used `InteractionManager` to mark when animations and gestures were in progress. This was primarily used to defer code that should run after transitions, such as loading data or rendering heavy components.
+
+However, `InteractionManager` has been deprecated in latest React Native versions, so we are removing support for this API in React Navigation 8. As an alternative, consumers can listen to events such as `transitionStart`, `transitionEnd` etc. when applicable:
+
+```diff lang=js
+- InteractionManager.runAfterInteractions(() => {
+- // code to run after transition
+- });
++ navigation.addListener('transitionEnd', () => {
++ // code to run after transition
++ });
+```
+
+Keep in mind that unlike `InteractionManager` which is global, the transition events are specific to a navigator.
+
+If you have a use case that cannot be solved with transition events, please open a [discussion on GitHub](https://github.com/react-navigation/react-navigation/discussions).
+
+#### The color arguments in various navigators now accept `ColorValue`
+
+Previously, color options in various navigators only accepted string values. In React Navigation 8, these options now accept `ColorValue` to match the [changes to theming](#themes-now-support-colorvalue-and-css-custom-properties).
+
+Unless you are using a custom theme with `PlatformColor` or `DynamicColorIOS` etc, this change only breaks TypeScript types:
+
+```diff lang=js
+- const tabBarIcon = ({ color, size }: { color: string, size: number }) => {
++ const tabBarIcon = ({ color, size }: { color: ColorValue, size: number }) => {
+ // ...
+};
+```
+
+See [Themes](themes.md#using-platform-colors) for more information about dynamic colors.
+
+#### The `onChangeText` callback has been renamed to `onChange` for `headerSearchBarOptions`
+
+The `onChangeText` option in `headerSearchBarOptions` was confusingly named after text input's
+`onChangeText`, but TextInput's `onChangeText` receives the new text as the first argument, whereas `headerSearchBarOptions.onChangeText` received an event object - similar to TextInput's `onChange`.
+
+To avoid confusion due to this inconsistency, the option has been renamed to `onChange`. To upgrade, simply rename the option:
+
+```diff lang=js
+createNativeStackNavigator({
+ screens: {
+ Search: {
+ screen: SearchScreen,
+ options: {
+ headerSearchBarOptions: {
+- onChangeText: (event) => {
++ onChange: (event) => {
+ const text = event.nativeEvent.text;
+ // ...
+ },
+ },
+ },
+ },
+ },
+});
+```
+
+This applies to all navigators that support `headerSearchBarOptions`, such as Native Stack Navigator with native header, and other navigators using `Header` from `@react-navigation/elements`.
+
+If you're using `Header` from `@react-navigation/elements` directly, the same change applies.
+
+#### APIs for customizing Navigation bar and status bar colors are removed from Native Stack Navigator
+
+Previously, Native Stack Navigator provided options to customize the appearance of the navigation bar and status bar on Android:
+
+- `navigationBarColor`
+- `navigationBarTranslucent`
+- `statusBarBackgroundColor`
+- `statusBarTranslucent`
+
+In Android 15 and onwards, edge-to-edge is now the default behavior, and will likely be enforced in future versions. Therefore, these options have been removed in React Navigation 8.
+
+You can use [`react-native-edge-to-edge`](https://github.com/zoontek/react-native-edge-to-edge) instead to configure status bar and navigation bar related settings.
+
+See [Native Stack Navigator](native-stack-navigator.md) for all available options.
+
+#### Drawer Navigator now accepts `overlayStyle` instead of `overlayColor`
+
+Previously, the Drawer Navigator accepted an `overlayColor` prop to customize the color of the overlay that appears when the drawer is open. It now accepts `overlayStyle` prop instead to provide more flexibility for styling the overlay:
+
+```diff lang=js
+- overlayColor="rgba(0, 0, 0, 0.5)"
++ overlayStyle={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
+```
+
+See [Drawer Navigator](drawer-navigator.md) for more details.
+
+### Miscellaneous
+
+#### Various deprecated APIs have been removed
+
+The following API that were marked as deprecated in React Navigation 7 have been removed:
+
+- `navigateDeprecated` from the navigation object has been removed. Use `navigate` instead. To preserve the previous behavior, you can pass `pop: true` as the third argument to `navigate`:
+
+ ```diff lang=js
+ - navigation.navigateDeprecated('Profile', { userId: 123 });
+ + navigation.navigate('Profile', { userId: 123 }, { pop: true });
+ ```
+
+- `getId` from the navigation object has been removed since the [`id` prop has been removed](#navigators-no-longer-accept-an-id-prop).
+
+- `navigationInChildEnabled` prop from `NavigationContainer` has been removed. This behavior is no longer supported.
+
+#### The linking config no longer requires a `prefixes` option
+
+Previously, the linking configuration required a `prefixes` option to specify the URL prefixes that the app should handle. This historical reason for this is to support Expo Go which uses a custom URL scheme.
+
+Since then, the recommended way to develop with Expo has been to use [Development Builds](https://docs.expo.dev/develop/development-builds/introduction/), which use the app's own URL scheme. So the `prefixes` option is not needed for most use cases.
+
+You can now omit the `prefixes` option in the linking configuration unless you're using Expo Go:
+
+
+
+
+```diff lang=js
+
+```
+
+
+
+
+```diff lang=js
+
+```
+
+
+
+
+The `prefixes` default to `['*']`, which will match any host starting with `http`, `https`, and custom schemes such as `myapp://`.
+
+See [Configuring links](configuring-links.md) for more details.
+
+#### Some exports are removed from `@react-navigation/elements`
+
+The `@react-navigation/elements` package has exported some components that were primarily intended for internal usage. These components have been removed from the public API:
+
+- `Background`
+
+ Background color can instead be applied by using it from `useTheme`.
+
+ ```diff lang=js
+ - import { Background } from '@react-navigation/elements';
+ + import { useTheme } from '@react-navigation/native';
+ // ...
+ - {children}
+ + const { colors } = useTheme();
+ +
+ + {children}
+ ```
+
+- `Screen`
+
+ You can render the `Header` component directly instead.
+
+- `SafeAreaProviderCompat`
+
+ You can use `SafeAreaProvider` from [`react-native-safe-area-context`](https://github.com/AppAndFlow/react-native-safe-area-context) directly instead.
+
+- `MissingIcon`
+
+ You can copy the implementation from the [source code](https://github.com/react-navigation/react-navigation/blob/main/packages/elements/src/MissingIcon.tsx) if you need a placeholder icon.
+
+Some of these components are still available and exported at `@react-navigation/elements/internal`, so you can continue using them if you really need. However, since they are not part of the public API, they don't follow semver and may change without warning in future releases.
+
+#### The `getDefaultHeaderHeight` utility now accepts an object instead of positional arguments
+
+The `getDefaultHeaderHeight` utility from `@react-navigation/elements` now accepts an object with named properties instead of positional arguments to improve readability"
+
+```diff lang=js
+- getDefaultHeaderHeight(layout, false, statusBarHeight);
++ getDefaultHeaderHeight({
++ landscape: false,
++ modalPresentation: false,
++ topInset: statusBarHeight
++ });
+```
+
+See [Elements docs](elements.md#getdefaultheaderheight) for more details.
+
+## New features
+
+### Common hooks now accept name of the screen
+
+The `useNavigation`, `useRoute`, and `useNavigationState` hooks can now optionally accept the name of the screen:
+
+```js
+const route = useRoute('Profile');
+```
+
+The name of the screen can be for the current screen or any of its parent screens. This makes it possible to get params and navigation state for a parent screen without needing to setup context to pass them down.
+
+If the provided screen name does not exist in any of the parent screens, it will throw an error, so any mistakes are caught early.
+
+When using static configuration, the types are automatically inferred based on the name of the screen.
+
+It's still possible to use these hooks without passing the screen name, same as before, and it will return the navigation or route for the current screen.
+
+See [`useNavigation`](use-navigation.md), [`useRoute`](use-route.md), and [`useNavigationState`](use-navigation-state.md) for more details.
+
+### New entry can be added to history stack with `pushParams` action
+
+The `pushParams` action updates the params and pushes a new entry to the history stack:
+
+```js
+navigation.pushParams({ filter: 'new' });
+```
+
+Unlike `setParams`, this does not merge the new params with the existing ones. Instead, it uses the new params object as-is.
+
+The action works in all navigators, such as stack, tab, and drawer. This allows to add a new entry to the history stack without needing to push a new screen instance.
+
+This can be useful in various scenario:
+
+- A product listing page with filters, where changing filters should create a new history entry so that users can go back to previous filter states.
+- A screen with a custom modal component, where the modal is not a separate screen in the navigator, but its state should be reflected in the URL and history.
+
+See [`pushParams` docs](navigation-actions.md#pushparams) for more details.
+
+### Themes now support `ColorValue` and CSS custom properties
+
+Previously, theme colors only supported string values. In React Navigation 8, theme colors now support `PlatformColor`, `DynamicColorIOS` on native, and CSS custom properties on Web for more flexibility.
+
+Example theme using `PlatformColor`:
+
+```js
+const MyTheme = {
+ ...DefaultTheme,
+ colors: Platform.select({
+ ios: () => ({
+ primary: PlatformColor('systemRed'),
+ background: PlatformColor('systemGroupedBackground'),
+ card: PlatformColor('tertiarySystemBackground'),
+ text: PlatformColor('label'),
+ border: PlatformColor('separator'),
+ notification: PlatformColor('systemRed'),
+ }),
+ android: () => ({
+ primary: PlatformColor('@android:color/system_primary_light'),
+ background: PlatformColor(
+ '@android:color/system_surface_container_light'
+ ),
+ card: PlatformColor('@android:color/system_background_light'),
+ text: PlatformColor('@android:color/system_on_surface_light'),
+ border: PlatformColor('@android:color/system_outline_variant_light'),
+ notification: PlatformColor('@android:color/holo_red_light'),
+ }),
+ default: () => DefaultTheme.colors,
+ })(),
+};
+```
+
+See [Themes](themes.md#using-platform-colors) for more details.
+
+### Groups now support `linking` option in static configuration
+
+The `linking` option can now be specified for groups in static configuration to define nested paths:
+
+```js
+const Stack = createStackNavigator({
+ groups: {
+ Settings: {
+ linking: { path: 'settings' },
+ screens: {
+ UserSettings: 'user',
+ AppSettings: 'app',
+ },
+ },
+ },
+});
+```
+
+This lets you prefix the paths of the screens in the group with a common prefix, e.g. `settings/` for `settings/user` and `settings/app`.
+
+See [Group](group.md) for more details.
+
+### Navigators now accept a `router` prop
+
+A router defines how the navigator updates its state based on navigation actions. Previously, custom routers could only be used by [creating a custom navigator](custom-navigators.md#extending-navigators).
+
+We later added an experimental `UNSTABLE_router` prop to various navigators to customize the router without needing to create a custom navigator. In React Navigation 8, we have dropped the `UNSTABLE_` prefix and made it a stable API.
+
+```js static2dynamic
+const MyStack = createNativeStackNavigator({
+ // highlight-start
+ router: (original) => ({
+ getStateForAction(state, action) {
+ if (action.type === 'NAVIGATE') {
+ // Custom logic for NAVIGATE action
+ }
+
+ // Fallback to original behavior
+ return original.getStateForAction(state, action);
+ },
+ }),
+ // highlight-end
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+```
+
+See [`Navigator` docs](navigator.md#router) for more details.
+
+### `Header` from `@react-navigation/elements` has been reworked
+
+The `Header` component from `@react-navigation/elements` has been reworked with various improvements:
+
+- It uses the new liquid glass effect on iOS 26
+- It supports `ColorValue` and CSS custom properties for colors
+- It supports `headerBlurEffect` on Web (previously only supported on iOS in Native Stack Navigator)
+- It no longer needs the layout of the screen to render correctly
+
+To match the iOS 26 design, the back button title is no longer shown by default on iOS 26.
+
+See [Elements](elements.md) for more details.
+
+### `react-native-tab-view` now supports a `renderAdapter` prop for custom adapters
+
+By default, `react-native-tab-view` uses [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view) for rendering pages on Android and iOS. However, it may not be suitable for all use cases.
+
+So it now supports a `renderAdapter` prop to provide a custom adapter for rendering pages. For example, you can use `ScrollViewAdapter` to use a `ScrollView` for rendering pages:
+
+```js
+import React from 'react';
+import { TabView, ScrollViewAdapter } from 'react-native-tab-view';
+
+export default function TabViewExample() {
+ const [index, setIndex] = React.useState(0);
+
+ return (
+
+ );
+}
+```
+
+You can also create your own custom adapter by implementing the required interface. See the [`react-native-tab-view` docs](tab-view.md) for more information.
diff --git a/versioned_docs/version-8.x/use-focus-effect.md b/versioned_docs/version-8.x/use-focus-effect.md
index 771a42aeca2..ec6d7aae01d 100755
--- a/versioned_docs/version-8.x/use-focus-effect.md
+++ b/versioned_docs/version-8.x/use-focus-effect.md
@@ -100,20 +100,22 @@ If you don't ignore the result, then you might end up with inconsistent data due
The `useFocusEffect` hook runs the effect as soon as the screen comes into focus. This often means that if there is an animation for the screen change, it might not have finished yet.
-React Navigation runs its animations in native thread, so it's not a problem in many cases. But if the effect updates the UI or renders something expensive, then it can affect the animation performance. In such cases, we can use [`InteractionManager`](https://reactnative.dev/docs/interactionmanager) to defer our work until the animations or gestures have finished:
+The navigators in React Navigation run animations in native thread when possible, so it's not a problem in most cases. But if the effect updates the UI or renders something expensive, then it can affect the animation performance. In such cases, you can listen to the `transitionEnd` event to defer your work until the transition has finished:
```js
useFocusEffect(
React.useCallback(() => {
- const task = InteractionManager.runAfterInteractions(() => {
- // Expensive task
+ const unsubscribe = navigation.addListener('transitionEnd', () => {
+ // Expensive task after transition finishes
});
- return () => task.cancel();
- }, [])
+ return unsubscribe;
+ }, [navigation])
);
```
+Keep in mind that the `transitionEnd` event is specific to stack navigators. For other navigators, you may need to use different approaches or events.
+
## How is `useFocusEffect` different from adding a listener for `focus` event
The `focus` event fires when a screen comes into focus. Since it's an event, your listener won't be called if the screen was already focused when you subscribed to the event. This also doesn't provide a way to perform a cleanup function when the screen becomes unfocused. You can subscribe to the `blur` event and handle it manually, but it can get messy. You will usually need to handle `componentDidMount` and `componentWillUnmount` as well in addition to these events, which complicates it even more.
diff --git a/versioned_docs/version-8.x/use-navigation-state.md b/versioned_docs/version-8.x/use-navigation-state.md
index c620118dc9a..e3d9f9a7ed2 100755
--- a/versioned_docs/version-8.x/use-navigation-state.md
+++ b/versioned_docs/version-8.x/use-navigation-state.md
@@ -15,18 +15,94 @@ Consider the navigator's state object to be internal and subject to change in a
:::
-It takes a selector function as an argument. The selector will receive the full [navigation state](navigation-state.md) and can return a specific value from the state:
+It can be used in two ways.
-```js
-const index = useNavigationState((state) => state.index);
+## Getting the navigation state by screen name
+
+The hook accepts the name of the current screen or any of its parent screens as the first argument to get the navigation state for the navigator containing that screen. The second argument is a selector function that receives the full [navigation state](navigation-state.md) and can return a specific value from the state:
+
+```js name="useNavigationState hook" snack static2dynamic
+import * as React from 'react';
+import { Button } from '@react-navigation/elements';
+import { View, Text } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+// codeblock-focus-start
+import { useNavigationState } from '@react-navigation/native';
+
+function CurrentRouteDisplay() {
+ // highlight-start
+ const focusedRouteName = useNavigationState(
+ 'Home',
+ (state) => state.routes[state.index]
+ );
+ // highlight-end
+
+ return Current route: {focusedRouteName} ;
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home Screen
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ return (
+
+ Profile Screen
+
+ navigation.goBack()}>Go back
+
+ );
+}
+
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
```
The selector function helps to reduce unnecessary re-renders, so your screen will re-render only when that's something you care about. If you actually need the whole state object, you can do this explicitly:
```js
-const state = useNavigationState((state) => state);
+const state = useNavigationState('Home', (state) => state);
```
+## Getting the current navigation state
+
+You can also use `useNavigationState` without a screen name to get the navigation state for the current screen's navigator. In this case, it takes a selector function as the only argument:
+
+```js
+const focusedRouteName = useNavigationState(
+ (state) => state.routes[state.index].name
+);
+```
+
+This is often useful for re-usable components that are used across multiple screens.
+
:::warning
This hook is useful for advanced cases and it's easy to introduce performance issues if you're not careful. For most of the cases, you don't need the navigator's state.
diff --git a/versioned_docs/version-8.x/use-navigation.md b/versioned_docs/version-8.x/use-navigation.md
index 03c019158df..100f3070272 100755
--- a/versioned_docs/version-8.x/use-navigation.md
+++ b/versioned_docs/version-8.x/use-navigation.md
@@ -9,7 +9,11 @@ import TabItem from '@theme/TabItem';
`useNavigation` is a hook that gives access to `navigation` object. It's useful when you cannot pass the `navigation` object as a prop to the component directly, or don't want to pass it in case of a deeply nested child.
-The `useNavigation` hook returns the `navigation` object of the screen where it's used:
+It can be used in two ways.
+
+## Getting the navigation object by screen name
+
+The hook accepts the name of the current screen or any of its parent screens to get the corresponding navigation object:
```js name="useNavigation hook" snack static2dynamic
import * as React from 'react';
@@ -22,7 +26,7 @@ import { useNavigation } from '@react-navigation/native';
function MyBackButton() {
// highlight-next-line
- const navigation = useNavigation();
+ const navigation = useNavigation('Profile');
return (
@@ -75,7 +79,19 @@ function App() {
export default App;
```
-Check how to setup `useNavigation` with TypeScript [here](typescript.md#annotating-usenavigation).
+## Getting the current navigation object
+
+You can also use `useNavigation` without any arguments to get the navigation object for the current screen:
+
+```js
+function MyComponent() {
+ const navigation = useNavigation();
+
+ return navigation.goBack()}>Go back ;
+}
+```
+
+This is often useful for re-usable components that are used across multiple screens.
See the documentation for the [`navigation` object](navigation-object.md) for more info.
diff --git a/versioned_docs/version-8.x/use-route.md b/versioned_docs/version-8.x/use-route.md
index 0a94305c5e2..1f2cf2fc681 100755
--- a/versioned_docs/version-8.x/use-route.md
+++ b/versioned_docs/version-8.x/use-route.md
@@ -9,9 +9,11 @@ import TabItem from '@theme/TabItem';
`useRoute` is a hook which gives access to `route` object. It's useful when you cannot pass down the `route` object from props to the component, or don't want to pass it in case of a deeply nested child.
-`useRoute()` returns the `route` object of the screen it's inside.
+It can be used in two ways.
-## Example
+## Getting the route object by screen name
+
+The hook accepts the name of the current screen or any of its parent screens to get the corresponding route object:
```js name="useRoute hook" snack static2dynamic
import * as React from 'react';
@@ -27,14 +29,14 @@ import { useRoute } from '@react-navigation/native';
function MyText() {
// highlight-next-line
- const route = useRoute();
+ const route = useRoute('Profile');
return {route.params.caption} ;
}
// codeblock-focus-end
function HomeScreen() {
- const navigation = useNavigation();
+ const navigation = useNavigation('Home');
return (
@@ -76,7 +78,19 @@ function App() {
export default App;
```
-Check how to setup `useRoute` with TypeScript [here](typescript.md#annotating-useroute).
+## Getting the current route object
+
+You can also use `useRoute` without any arguments to get the route object for the current screen:
+
+```js
+function MyComponent() {
+ const route = useRoute();
+
+ return {route.name} ;
+}
+```
+
+This is often useful for re-usable components that are used across multiple screens.
See the documentation for the [`route` object](route-object.md) for more info.
@@ -94,7 +108,7 @@ class MyText extends React.Component {
// Wrap and export
export default function (props) {
- const route = useRoute();
+ const route = useRoute('Profile');
return ;
}
diff --git a/versioned_sidebars/version-8.x-sidebars.json b/versioned_sidebars/version-8.x-sidebars.json
index 2467400dbfe..b0bed7c7f5b 100644
--- a/versioned_sidebars/version-8.x-sidebars.json
+++ b/versioned_sidebars/version-8.x-sidebars.json
@@ -36,13 +36,12 @@
"testing",
"typescript",
"troubleshooting",
- "upgrading-from-6.x"
+ "upgrading-from-7.x"
],
"Navigators": [
"stack-navigator",
"native-stack-navigator",
"bottom-tab-navigator",
- "native-bottom-tab-navigator",
"drawer-navigator",
"material-top-tab-navigator"
],