();
+
+ const html = ReactDOMServer.renderToString(
+
+ {element}
+
+ );
+
+ const css = ReactDOMServer.renderToStaticMarkup(getStyleElement());
+
+ const options = ref.current?.getCurrentOptions();
+
+ const document = `
+
+
+
+
+
+ ${css}
+ ${options.title}
+
+
+ ${html}
+
+`;
+
+ ctx.body = document;
+});
+```
+
+Make sure that you have specified a `title` option for your screens:
+
+
+
+
+```js
+const Stack = createNativeStackNavigator({
+ screens: {
+ Home: {
+ screen: HomeScreen,
+ options: {
+ // highlight-next-line
+ title: 'My App',
+ },
+ },
+ Profile: {
+ screen: ProfileScreen,
+ options: ({ route }) => ({
+ // highlight-next-line
+ title: `${route.params.name}'s Profile`,
+ }),
+ },
+ },
+});
+```
+
+
+
+
+```js
+
+
+ ({
+ // highlight-next-line
+ title: `${route.params.name}'s Profile`,
+ })}
+ />
+
+```
+
+
+
+
+## Handling 404 or other status codes
+
+When [rendering a screen for an invalid URL](configuring-links.md#handling-unmatched-routes-or-404), we should also return a `404` status code from the server.
+
+First, we need to create a context where we'll attach the status code. To do this, place the following code in a separate file that we will be importing on both the server and client:
+
+```js
+import * as React from 'react';
+
+const StatusCodeContext = React.createContext();
+
+export default StatusCodeContext;
+```
+
+Then, we need to use the context in our `NotFound` screen. Here, we add a `code` property with the value of `404` to signal that the screen was not found:
+
+```js
+function NotFound() {
+ const status = React.useContext(StatusCodeContext);
+
+ if (status) {
+ staus.code = 404;
+ }
+
+ return (
+
+ Oops! This URL doesn't exist.
+
+ );
+}
+```
+
+You could also attach additional information in this object if you need to.
+
+Next, we need to create a status object to pass in the context on our server. By default, we'll set the `code` to `200`. Then pass the object in `StatusCodeContext.Provider` which should wrap the element with `ServerContainer`:
+
+```js
+// Create a status object
+const status = { code: 200 };
+
+const html = ReactDOMServer.renderToString(
+ // Pass the status object via context
+
+
+ {element}
+
+
+);
+
+// After rendering, get the status code and use it for server's response
+ctx.status = status.code;
+```
+
+After we render the app with `ReactDOMServer.renderToString`, the `code` property of the `status` object will be updated to be `404` if the `NotFound` screen was rendered.
+
+You can follow a similar approach for other status codes too, for example, `401` for unauthorized etc.
+
+## Summary
+
+- Use the `location` prop on `ServerContainer` to render correct screens based on the incoming request.
+- Attach a `ref` to the `ServerContainer` get options for the current screen.
+- Use context to attach more information such as status code.
diff --git a/versioned_docs/version-8.x/shared-element-transitions.md b/versioned_docs/version-8.x/shared-element-transitions.md
new file mode 100644
index 00000000000..813b90f499e
--- /dev/null
+++ b/versioned_docs/version-8.x/shared-element-transitions.md
@@ -0,0 +1,229 @@
+---
+id: shared-element-transitions
+title: Animating elements between screens
+sidebar_label: Shared element transitions
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+This guide covers how to animate elements between screens. This feature is known as a [Shared Element Transition](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/) and it's implemented in the [`@react-navigation/native-stack`](native-stack-navigator.md) with [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/).
+
+:::warning
+
+As of writing this guide, Shared Element Transitions are considered an experimental feature not recommended for production use.
+
+Shared Element Transitions are currently only supported on **old React Native architecture** (Paper).
+
+:::
+
+
+
+
+
+## Pre-requisites
+
+Before continuing this guide make sure your app meets these criteria:
+
+- You are using [`@react-navigation/native-stack`](native-stack-navigator.md). The Shared Element Transitions feature isn't supported in JS-based [`@react-navigation/stack`](stack-navigator.md).
+- You have [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started) **v3.0.0 or higher** installed and configured.
+
+## Minimal example
+
+To create a shared transition:
+
+1. Use `Animated` components imported from `react-native-reanimated`.
+2. Assign the same `sharedTransitionTag` to elements on different screens.
+3. Navigate between screens. The transition will start automatically.
+
+
+
+
+```js name="Shared transition"
+import * as React from 'react';
+import { View, StyleSheet } from 'react-native';
+import {
+ useNavigation,
+ createStaticNavigation,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+
+import Animated from 'react-native-reanimated';
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ navigation.navigate('Details')}>
+ Go to Details
+
+
+
+ );
+}
+
+function DetailsScreen() {
+ const navigation = useNavigation('Details');
+
+ return (
+
+ navigation.goBack()}>Go back
+
+
+ );
+}
+
+// highlight-start
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Details: DetailsScreen,
+ },
+});
+// highlight-end
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ },
+});
+```
+
+
+
+
+```js name="Shared transition"
+import * as React from 'react';
+import { View, StyleSheet } from 'react-native';
+import { NavigationContainer, useNavigation } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+
+import Animated from 'react-native-reanimated';
+
+// highlight-next-line
+const Stack = createNativeStackNavigator();
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ navigation.navigate('Details')}>
+ Go to Details
+
+
+
+ );
+}
+
+function DetailsScreen() {
+ const navigation = useNavigation('Details');
+
+ return (
+
+ navigation.goBack()}>Go back
+
+
+ );
+}
+
+export default function App() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ },
+});
+```
+
+
+
+
+`sharedTransitionTag` is a string that has to be unique in the context of a single screen, but has to match elements between screens. This prop allows Reanimated to identify and animate the elements, similarly to the [`key`](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) property, which tells React which element in the list is which.
+
+## Customizing the transition
+
+By default, the transition animates the `width`, `height`, `originX`, `originY` and `transform` properties using `withTiming` with a 500 ms duration. You can easily customize `width`, `height`, `originX`, and `originY` props. Customizing `transform` is also possible but it's far beyond the scope of this guide.
+
+:::warning
+
+Custom SharedTransition API is not finalized and might change in a future release.
+
+:::
+
+To customize the transition you need to pass all the properties besides `transform`.
+
+```jsx
+import { SharedTransition } from 'react-native-reanimated';
+
+const customTransition = SharedTransition.custom((values) => {
+ 'worklet';
+ return {
+ height: withSpring(values.targetHeight),
+ width: withSpring(values.targetWidth),
+ originX: withSpring(values.targetOriginX),
+ originY: withSpring(values.targetOriginY),
+ };
+});
+
+function HomeScreen() {
+ return (
+
+ );
+}
+```
+
+## Reference
+
+You can find a full Shared Element Transitions reference in the [React Native Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/).
+
+## Alternatives
+
+Alternatively, you can use [`react-native-shared-element`](https://github.com/IjzerenHein/react-native-shared-element) library with a [React Navigation binding](https://github.com/IjzerenHein/react-navigation-shared-element) which implements Shared Element Transitions in a JS-based `@react-navigation/stack` navigator. This solution, however, isn't actively maintained.
+
+The [`react-native-navigation`](https://github.com/wix/react-native-navigation) also comes with support for Shared Element Transitions. You can read more about it [here](https://wix.github.io/react-native-navigation/docs/style-animations#shared-element-transitions).
diff --git a/versioned_docs/version-8.x/stack-actions.md b/versioned_docs/version-8.x/stack-actions.md
new file mode 100755
index 00000000000..1f8ae3bcc23
--- /dev/null
+++ b/versioned_docs/version-8.x/stack-actions.md
@@ -0,0 +1,469 @@
+---
+id: stack-actions
+title: StackActions reference
+sidebar_label: StackActions
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+`StackActions` is an object containing methods for generating actions specific to stack-based navigators. Its methods expand upon the actions available in [`CommonActions`](navigation-actions.md).
+
+The following actions are supported:
+
+## replace
+
+The `replace` action allows to replace a route in the [navigation state](navigation-state.md). It takes the following arguments:
+
+- `name` - _string_ - A destination name of the route that has been registered somewhere.
+- `params` - _object_ - Params to pass to the destination route.
+
+```js name="Stack actions replace" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ StackActions,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+function HomeScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Home!
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ // codeblock-focus-start
+ navigation.dispatch(
+ StackActions.replace('Profile', { user: 'Wojtek' })
+ );
+ // codeblock-focus-end
+ }}
+ >
+ Replace with Profile
+
+
+ );
+}
+
+function ProfileScreen({ route }) {
+ const navigation = useNavigation();
+ return (
+
+ Profile!
+ {route.params.user}'s profile
+ navigation.dispatch(StackActions.pop(1))}>
+ Pop one screen from stack
+
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push same screen on the stack
+
+ navigation.dispatch(StackActions.popToTop())}>
+ Pop to top
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
+
+If you want to replace a particular route, you can add a `source` property referring to the route key and `target` property referring to the navigation state key:
+
+```js
+import { StackActions } from '@react-navigation/native';
+
+navigation.dispatch({
+ ...StackActions.replace('Profile', {
+ user: 'jane',
+ }),
+ source: route.key,
+ target: navigation.getState().key,
+});
+```
+
+If the `source` property is explicitly set to `undefined`, it'll replace the focused route.
+
+## push
+
+The `push` action adds a route on top of the stack and navigates forward to it. This differs from `navigate` in that `navigate` will pop back to earlier in the stack if a route of the given name is already present there. `push` will always add on top, so a route can be present multiple times.
+
+- `name` - _string_ - Name of the route to push onto the stack.
+- `params` - _object_ - Screen params to pass to the destination route.
+
+```js name="Stack actions push" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ StackActions,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+function HomeScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Home!
+ {
+ // codeblock-focus-start
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ // codeblock-focus-end
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ navigation.dispatch(
+ StackActions.replace('Profile', { user: 'Wojtek' })
+ );
+ }}
+ >
+ Replace with Profile
+
+
+ );
+}
+
+function ProfileScreen({ route }) {
+ const navigation = useNavigation();
+ return (
+
+ Profile!
+ {route.params.user}'s profile
+ navigation.dispatch(StackActions.pop(1))}>
+ Pop one screen from stack
+
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push same screen on the stack
+
+ navigation.dispatch(StackActions.popToTop())}>
+ Pop to top
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
+
+## pop
+
+The `pop` action takes you back to a previous screen in the stack. It takes one optional argument (`count`), which allows you to specify how many screens to pop back by.
+
+```js name="Stack actions pop" snack static2dynamic
+import * as React from 'react';
+import { Button } from '@react-navigation/elements';
+import { View, Text } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+ StackActions,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+function HomeScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Home!
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ navigation.dispatch(
+ StackActions.replace('Profile', { user: 'Wojtek' })
+ );
+ }}
+ >
+ Replace with Profile
+
+
+ );
+}
+
+function ProfileScreen({ route }) {
+ const navigation = useNavigation();
+ return (
+
+ Profile!
+ {route.params.user}'s profile
+ {
+ // codeblock-focus-start
+ navigation.dispatch(StackActions.pop(1));
+ // codeblock-focus-end
+ }}
+ >
+ Pop one screen from stack
+
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push same screen on the stack
+
+ navigation.dispatch(StackActions.popToTop())}>
+ Pop to top
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
+
+## popTo
+
+The `popTo` action takes you back to a previous screen in the stack by the name. It also allows you to pass params to the route.
+
+If a matching screen is not found in the stack, this will pop the current screen and add a new screen with the specified name and params - essentially behaving like a [`replace`](#replace). This ensures that the app doesn't break if a previous screen with the name did not exist - which can happen when the screen was opened from a deep link or push notification, or when used on the web etc.
+
+The method accepts the following arguments:
+
+- `name` - _string_ - Name of the route to navigate to.
+- `params` - _object_ - Screen params to pass to the destination route.
+- `options` - Options object containing the following properties:
+ - `merge` - _boolean_ - Whether params should be merged with the existing route params, or replace them (when navigating to an existing screen). Defaults to `false`.
+
+```js name="Stack actions popTo" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ StackActions,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+function HomeScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Home!
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ navigation.dispatch(StackActions.push('Settings'));
+ }}
+ >
+ Push Settings on the stack
+
+
+ );
+}
+
+function ProfileScreen({ route }) {
+ const navigation = useNavigation();
+ return (
+
+ Profile!
+ {route?.params?.user || 'Guest'}'s profile
+ {
+ navigation.dispatch(StackActions.push('Settings'));
+ }}
+ >
+ Push Settings on the stack
+
+ {
+ // codeblock-focus-start
+ navigation.dispatch(StackActions.popTo('Profile', { user: 'jane' }));
+ // codeblock-focus-end
+ }}
+ >
+ Pop to Profile with params
+
+
+ );
+}
+
+function SettingsScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Settings!
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ navigation.dispatch(StackActions.popTo('Profile', { user: 'jane' }));
+ }}
+ >
+ Pop to Profile with params
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
+
+## popToTop
+
+The `popToTop` action takes you back to the first screen in the stack, dismissing all the others. It's functionally identical to `StackActions.pop({n: currentIndex})`.
+
+```js name="Stack actions popToTop" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ StackActions,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+function HomeScreen() {
+ const navigation = useNavigation();
+ return (
+
+ Home!
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push Profile on the stack
+
+ {
+ navigation.dispatch(
+ StackActions.replace('Profile', { user: 'Wojtek' })
+ );
+ }}
+ >
+ Replace with Profile
+
+
+ );
+}
+
+function ProfileScreen({ route }) {
+ const navigation = useNavigation();
+ return (
+
+ Profile!
+ {route.params.user}'s profile
+ navigation.dispatch(StackActions.pop(1))}>
+ Pop one screen from stack
+
+ {
+ navigation.dispatch(StackActions.push('Profile', { user: 'Wojtek' }));
+ }}
+ >
+ Push same screen on the stack
+
+ {
+ // codeblock-focus-start
+ navigation.dispatch(StackActions.popToTop());
+ // codeblock-focus-end
+ }}
+ >
+ Pop to top
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/stack-navigator.md b/versioned_docs/version-8.x/stack-navigator.md
new file mode 100755
index 00000000000..f843066c7bc
--- /dev/null
+++ b/versioned_docs/version-8.x/stack-navigator.md
@@ -0,0 +1,1350 @@
+---
+id: stack-navigator
+title: Stack Navigator
+sidebar_label: Stack
+---
+
+Stack Navigator provides a way for your app to transition between screens where each new screen is placed on top of a stack.
+
+By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, use OS default animation on Android. But the [animations can be customized](#animation-related-options) to match your needs.
+
+
+
+
+
+
+
+
+
+One thing to keep in mind is that while `@react-navigation/stack` is extremely customizable, it's implemented in JavaScript. While it runs animations and gestures using natively, the performance may not be as fast as a native implementation. This may not be an issue for a lot of apps, but if you're experiencing performance issues during navigation, consider using [`@react-navigation/native-stack`](native-stack-navigator.md) instead - which uses native navigation primitives.
+
+## 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/stack`](https://github.com/react-navigation/react-navigation/tree/main/packages/stack):
+
+```bash npm2yarn
+npm install @react-navigation/stack
+```
+
+The navigator depends on [`react-native-gesture-handler`](https://docs.swmansion.com/react-native-gesture-handler/) for gestures and optionally [`@react-native-masked-view/masked-view`](https://github.com/react-native-masked-view/masked-view) for [UIKit style animations for the header](#headerstyleinterpolator).
+
+
+
+
+If you have a Expo managed project, in your project directory, run:
+
+```bash
+npx expo install react-native-gesture-handler @react-native-masked-view/masked-view
+```
+
+
+
+
+If you have a bare React Native project, in your project directory, run:
+
+```bash npm2yarn
+npm install react-native-gesture-handler @react-native-masked-view/masked-view
+```
+
+
+
+
+If you're on a Mac and developing for iOS, you also need to install [pods](https://cocoapods.org/) to complete the linking.
+
+```bash
+npx pod-install ios
+```
+
+## Usage
+
+To use this navigator, import it from `@react-navigation/stack`:
+
+```js name="Stack Navigator" snack static2dynamic
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import { createStackNavigator } from '@react-navigation/stack';
+
+// codeblock-focus-end
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home Screen
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ return (
+
+ Profile Screen
+
+ );
+}
+
+// codeblock-focus-start
+const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+// codeblock-focus-end
+
+const Navigation = createStaticNavigation(MyStack);
+
+export default function App() {
+ return ;
+}
+```
+
+## API Definition
+
+### Props
+
+In addition to the [common props](navigator.md#configuration) shared by all navigators, the stack navigator accepts the following additional props:
+
+#### `detachInactiveScreens`
+
+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`.
+
+If you need to disable this optimization for specific screens (e.g. you want to screen to stay in view even when unfocused) [`detachPreviousScreen`](#detachpreviousscreen) option.
+
+### 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 `Stack.Navigator` or `options` prop of `Stack.Screen`.
+
+#### `title`
+
+String that can be used as a fallback for `headerTitle`.
+
+#### `cardShadowEnabled`
+
+Use this prop to have visible shadows during transitions. Defaults to `true`.
+
+#### `cardOverlayEnabled`
+
+Use this prop to have a semi-transparent dark overlay visible under the card during transitions. Defaults to `true` on Android and `false` on iOS.
+
+#### `cardOverlay`
+
+Function which returns a React Element to display as the overlay for the card. Make sure to set `cardOverlayEnabled` to `true` when using this.
+
+#### `cardStyle`
+
+Style object for the card in stack. You can provide a custom background color to use instead of the default background here.
+
+You can also specify `{ backgroundColor: 'transparent' }` to make the previous screen visible underneath (for transparent modals). This is useful to implement things like modal dialogs. You should also specify `presentation: 'modal'` in the options when using a transparent background so previous screens aren't detached and stay visible underneath.
+
+On Web, the height of the screen isn't limited to the height of the viewport. This is by design to allow the browser's address bar to hide when scrolling. If this isn't desirable behavior, you can set `cardStyle` to `{ flex: 1 }` to force the screen to fill the viewport.
+
+#### `presentation`
+
+This is shortcut option which configures several options to configure the style for rendering and transitions:
+
+- `card`: Use the default OS animations for iOS and Android screen transitions.
+- `modal`: Use Modal animations. This changes a few things:
+ - Sets `headerMode` to `screen` for the screen unless specified otherwise.
+ - Changes the screen animation to match the platform behavior for modals.
+- `transparentModal`: Similar to `modal`. This changes following things:
+ - Sets `headerMode` to `screen` for the screen unless specified otherwise.
+ - Sets background color of the screen to transparent, so previous screen is visible
+ - Adjusts the `detachPreviousScreen` option so that the previous screen stays rendered.
+ - Prevents the previous screen from animating from its last position.
+ - Changes the screen animation to a vertical slide animation.
+
+See [Transparent modals](#transparent-modals) for more details on how to customize `transparentModal`.
+
+#### `animationTypeForReplace`
+
+The type of animation to use when this screen replaces another screen. It takes the following values:
+
+- `push` - The animation of a new screen being pushed will be used
+- `pop` - The animation of a screen being popped will be used
+
+Defaults to `push`.
+
+When `pop` is used, the `pop` animation is applied to the screen being replaced.
+
+#### `gestureEnabled`
+
+Whether you can use gestures to dismiss this screen. Defaults to `true` on iOS, `false` on Android.
+
+Gestures are not supported on Web.
+
+#### `gestureResponseDistance`
+
+Number to override the distance of touch start from the edge of the screen to recognize gestures.
+
+It'll configure either the horizontal or vertical distance based on the [`gestureDirection`](#gesturedirection) value.
+
+The default values are:
+
+- `50` - when `gestureDirection` is `horizontal` or `horizontal-inverted`
+- `135` - when `gestureDirection` is `vertical` or `vertical-inverted`
+
+This is not supported on Web.
+
+#### `gestureVelocityImpact`
+
+Number which determines the relevance of velocity for the gesture. Defaults to 0.3.
+
+This is not supported on Web.
+
+#### `gestureDirection`
+
+Direction of the gestures. Refer the [Animations section](#animations) for details.
+
+This is not supported on Web.
+
+#### `transitionSpec`
+
+Configuration object for the screen transition. Refer the [Animations section](#animations) for details.
+
+#### `cardStyleInterpolator`
+
+Interpolated styles for various parts of the card. Refer the [Animations section](#animations) for details.
+
+#### `headerStyleInterpolator`
+
+Interpolated styles for various parts of the header. Refer the [Animations section](#animations) for details.
+
+#### `keyboardHandlingEnabled`
+
+If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen. Defaults to `true`.
+
+#### `detachPreviousScreen`
+
+Boolean used to indicate whether to detach the previous screen from the view hierarchy to save memory. Set it to `false` if you need the previous screen to be seen through the active screen. Only applicable if `detachInactiveScreens` isn't set to `false`.
+
+This is automatically adjusted when using [`presentation`](#presentation) as `transparentModal` or `modal` to keep the required screens visible. Defaults to `true` in other cases.
+
+#### `freezeOnBlur`
+
+Boolean indicating whether to prevent inactive screens from re-rendering. Defaults to `false`.
+Defaults to `true` when `enableFreeze()` from `react-native-screens` package is run at the top of the application.
+
+Only supported on iOS and Android.
+
+### 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 `Stack.Navigator` or `options` prop of `Stack.Screen`. You don't have to be using `@react-navigation/elements` directly to use these options, they are just documented in that page.
+
+In addition to those, the following options are also supported in stack:
+
+#### `header`
+
+Custom header to use instead of the default header.
+
+This accepts a function that returns a React Element to display as a header. The function receives an object containing the following properties as the argument:
+
+- `navigation` - The navigation object for the current screen.
+- `route` - The route object for the current screen.
+- `options` - The options for the current screen
+- `layout` - Dimensions of the screen, contains `height` and `width` properties.
+- `progress` Animated nodes representing the progress of the animation.
+- `back` - Options for the back button, contains an object with a `title` property to use for back button label.
+- `styleInterpolator` - Function which returns interpolated styles for various elements in the header.
+
+Make sure to set `headerMode` to `screen` as well when using a custom header (see below for more details).
+
+Example:
+
+```js
+import { getHeaderTitle } from '@react-navigation/elements';
+
+// ..
+
+header: ({ navigation, route, options, back }) => {
+ const title = getHeaderTitle(options, route.name);
+
+ return (
+ : undefined
+ }
+ style={options.headerStyle}
+ />
+ );
+};
+```
+
+To set a custom header for all the screens in the navigator, you can specify this option in the `screenOptions` prop of the navigator.
+
+When using a custom header, there are 2 things to keep in mind:
+
+##### Specify a `height` in `headerStyle` to avoid glitches
+
+If your header's height differs from the default header height, then you might notice glitches due to measurement being async. Explicitly specifying the height will avoid such glitches.
+
+Example:
+
+```js
+headerStyle: {
+ height: 80, // Specify the height of your custom header
+};
+```
+
+Note that this style is not applied to the header by default since you control the styling of your custom header. If you also want to apply this style to your header, use `headerStyle` from the props.
+
+##### Set `headerMode` to `float` for custom header animations
+
+By default, there is one floating header which renders headers for multiple screens on iOS for non-modals. These headers include animations to smoothly switch to one another.
+
+If you specify a custom header, React Navigation will change it to `screen` automatically so that the header animated along with the screen instead. This means that you don't have to implement animations to animate it separately.
+
+But you might want to keep the floating header to have a different transition animation between headers. To do that, you'll need to specify `headerMode: 'float'` in the options, and then interpolate on the `progress.current` and `progress.next` props in your custom header. For example, following will cross-fade the header:
+
+```js
+const opacity = Animated.add(progress.current, progress.next || 0).interpolate({
+ inputRange: [0, 1, 2],
+ outputRange: [0, 1, 0],
+});
+
+return (
+ {/* Header content */}
+);
+```
+
+#### `headerMode`
+
+Specifies how the header should be rendered:
+
+- `float` - The header is rendered above the screen and animates independently of the screen. This is default on iOS for non-modals.
+- `screen` - The header is rendered as part of the screen and animates together with the screen. This is default on other platforms.
+
+#### `headerShown`
+
+Whether to show or hide the header for the screen. The header is shown by default. Setting this to `false` hides the header.
+
+#### `headerBackAllowFontScaling`
+
+Whether back button title font should scale to respect Text Size accessibility settings. Defaults to false.
+
+#### `headerBackAccessibilityLabel`
+
+Accessibility label for the header back button.
+
+#### `headerBackImage`
+
+Function which returns a React Element to display custom image in header's back button. When a function is used, it receives the `tintColor` in it's argument object. Defaults to Image component with back image source, which is the default back icon image for the platform (a chevron on iOS and an arrow on Android).
+
+#### `headerBackTitle`
+
+Title string used by the back button on iOS. Defaults to the previous scene's title. Use `headerBackButtonDisplayMode` to customize the behavior.
+
+#### `headerTruncatedBackTitle`
+
+Title string used by the back button when `headerBackTitle` doesn't fit on the screen. `"Back"` by default.
+
+#### `headerBackButtonDisplayMode`
+
+How the back button displays icon and title.
+
+Supported values:
+
+- `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).
+- `minimal`: Always displays only the icon without a title.
+
+Defaults to `default` on iOS, and `minimal` on Android.
+
+#### `headerBackTitleStyle`
+
+Style object for the back title.
+
+### Events
+
+The navigator can [emit events](navigation-events.md) on certain actions. Supported events are:
+
+#### `transitionStart`
+
+This event is fired when the transition animation starts for the current screen.
+
+Event data:
+
+- `e.data.closing` - Boolean indicating whether the screen is being opened or closed.
+
+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.
+
+Event data:
+
+- `e.data.closing` - Boolean indicating whether the screen was opened or closed.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('transitionEnd', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+#### `gestureStart`
+
+This event is fired when the swipe gesture starts for the current screen.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('gestureStart', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+#### `gestureEnd`
+
+This event is fired when the swipe gesture ends for the current screen. e.g. a screen was successfully dismissed.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('gestureEnd', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+#### `gestureCancel`
+
+This event is fired when the swipe gesture is cancelled for the current screen. e.g. a screen wasn't dismissed by the gesture.
+
+Example:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('gestureCancel', (e) => {
+ // Do something
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+### Helpers
+
+The stack navigator adds the following methods to the navigation object:
+
+#### `replace`
+
+Replaces the current screen with a new screen in the stack. The method accepts the following arguments:
+
+- `name` - _string_ - Name of the route to push onto the stack.
+- `params` - _object_ - Screen params to pass to the destination route.
+
+```js
+navigation.replace('Profile', { owner: 'Michaś' });
+```
+
+#### `push`
+
+Pushes a new screen to the top of the stack and navigate to it. The method accepts the following arguments:
+
+- `name` - _string_ - Name of the route to push onto the stack.
+- `params` - _object_ - Screen params to pass to the destination route.
+
+```js
+navigation.push('Profile', { owner: 'Michaś' });
+```
+
+#### `pop`
+
+Pops the current screen from the stack and navigates back to the previous screen. It takes one optional argument (`count`), which allows you to specify how many screens to pop back by.
+
+```js
+navigation.pop();
+```
+
+#### `popTo`
+
+Navigates back to a previous screen in the stack by popping screens after it. The method accepts the following arguments:
+
+- `name` - _string_ - Name of the route to navigate to.
+- `params` - _object_ - Screen params to pass to the destination route.
+- `options` - Options object containing the following properties:
+ - `merge` - _boolean_ - Whether params should be merged with the existing route params, or replace them (when navigating to an existing screen). Defaults to `false`.
+
+If a matching screen is not found in the stack, this will pop the current screen and add a new screen with the specified name and params.
+
+```js
+navigation.popTo('Profile', { owner: 'Michaś' });
+```
+
+#### `popToTop`
+
+Pops all of the screens in the stack except the first one and navigates to it.
+
+```js
+navigation.popToTop();
+```
+
+### Hooks
+
+The stack navigator exports the following hooks:
+
+#### `useCardAnimation`
+
+This hook returns values related to the screen's animation. It contains the following properties:
+
+- `current` - Values for the current screen:
+ - `progress` - Animated node representing the progress value of the current screen.
+- `next` - Values for the screen after this one in the stack. This can be `undefined` in case the screen animating is the last one.
+ - `progress` - Animated node representing the progress value of the next screen.
+- `closing` - Animated node representing whether the card is closing. `1` when closing, `0` if not.
+- `swiping` - Animated node representing whether the card is being swiped. `1` when swiping, `0` if not.
+- `inverted` - Animated node representing whether the card is inverted. `-1` when inverted, `1` if not.
+- `index` - The index of the card in the stack.
+- `layouts` - Layout measurements for various items we use for animation.
+ - `screen` - Layout of the whole screen. Contains `height` and `width` properties.
+- `insets` - Layout of the safe area insets. Contains `top`, `right`, `bottom` and `left` properties.
+
+See [Transparent modals](#transparent-modals) for an example of how to use this hook.
+
+## Animations
+
+You can specify the `animation` option to customize the transition animation for screens being pushed or popped.
+
+Supported values for `animation` are:
+
+- `default` - Default animation based on the platform and OS version.
+- `fade` - Simple fade animation for dialogs.
+- `fade_from_bottom` - Standard Android-style fade-in from the bottom for Android Oreo.
+- `fade_from_right` - Standard Android-style fade-in from the right for Android 14.
+- `reveal_from_bottom` - Standard Android-style reveal from the bottom for Android Pie.
+- `scale_from_center` - Scale animation from the center.
+- `slide_from_right` - Standard iOS-style slide in from the right.
+- `slide_from_left` - Similar to `slide_from_right`, but the screen will slide in from the left.
+- `slide_from_bottom` - Slide animation from the bottom for modals and bottom sheets.
+- `none` - The screens are pushed or popped immediately without any animation.
+
+By default, Android and iOS use the `default` animation and other platforms use `none`.
+
+If you need more control over the animation, you can customize individual parts of the animation using the various animation-related options:
+
+### Animation related options
+
+Stack Navigator exposes various options to configure the transition animation when a screen is added or removed. These transition animations can be customized on a per-screen basis by specifying the options in the `options` prop for each screen.
+
+- `gestureDirection` - The direction of swipe gestures:
+ - `horizontal` - The gesture to close the screen will start from the left, and from the right in RTL. For animations, screen will slide from the right with `SlideFromRightIOS`, and from the left in RTL.
+ - `horizontal-inverted` - The gesture to close the screen will start from the right, and from the left in RTL. For animations, screen will slide from the left with `SlideFromRightIOS`, and from the right in RTL as the direction is inverted.
+ - `vertical` - The gesture to close the screen will start from the top. For animations, screen will slide from the bottom.
+ - `vertical-inverted` - The gesture to close the screen will start from the bottom. For animations, screen will slide from the top.
+
+ You may want to specify a matching horizontal/vertical animation along with `gestureDirection` as well. For the animations included in the library, if you set `gestureDirection` to one of the inverted ones, it'll also flip the animation direction.
+
+- `transitionSpec` - An object which specifies the animation type (`timing` or `spring`) and their options (such as `duration` for `timing`). It takes 2 properties:
+ - `open` - Configuration for the transition when adding a screen
+ - `close` - Configuration for the transition when removing a screen.
+
+ Each of the object should specify 2 properties:
+ - `animation` - The animation function to use for the animation. Supported values are `timing` and `spring`.
+ - `config` - The configuration object for the timing function. For `timing`, it can be `duration` and `easing`. For `spring`, it can be `stiffness`, `damping`, `mass`, `overshootClamping`, `restDisplacementThreshold` and `restSpeedThreshold`.
+
+ A config which uses spring animation looks like this:
+
+ ```js
+ const config = {
+ animation: 'spring',
+ config: {
+ stiffness: 1000,
+ damping: 500,
+ mass: 3,
+ overshootClamping: true,
+ restDisplacementThreshold: 0.01,
+ restSpeedThreshold: 0.01,
+ },
+ };
+ ```
+
+ We can pass this config in the `transitionSpec` option:
+
+ ```js name="Custom Transition Config" snack static2dynamic
+ import * as React from 'react';
+ import { Text, View } from 'react-native';
+ import {
+ createStaticNavigation,
+ useNavigation,
+ } from '@react-navigation/native';
+ import { Button } from '@react-navigation/elements';
+ import { createStackNavigator } from '@react-navigation/stack';
+
+ 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
+
+ );
+ }
+
+ // codeblock-focus-start
+ const config = {
+ animation: 'spring',
+ config: {
+ stiffness: 1000,
+ damping: 500,
+ mass: 3,
+ overshootClamping: true,
+ restDisplacementThreshold: 0.01,
+ restSpeedThreshold: 0.01,
+ },
+ };
+
+ const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ transitionSpec: {
+ open: config,
+ close: config,
+ },
+ },
+ },
+ },
+ });
+ // codeblock-focus-end
+
+ const Navigation = createStaticNavigation(MyStack);
+
+ export default function App() {
+ return ;
+ }
+ ```
+
+- `cardStyleInterpolator` - This is a function which specifies interpolated styles for various parts of the card. This allows you to customize the transitions when navigating from screen to screen. It is expected to return at least empty object, possibly containing interpolated styles for container, the card itself, overlay and shadow. Supported properties are:
+ - `containerStyle` - Style for the container view wrapping the card.
+ - `cardStyle` - Style for the view representing the card.
+ - `overlayStyle` - Style for the view representing the semi-transparent overlay below
+ - `shadowStyle` - Style for the view representing the card shadow.
+
+ The function receives the following properties in its argument:
+ - `current` - Values for the current screen:
+ - `progress` - Animated node representing the progress value of the current screen.
+ - `next` - Values for the screen after this one in the stack. This can be `undefined` in case the screen animating is the last one.
+ - `progress` - Animated node representing the progress value of the next screen.
+ - `index` - The index of the card in the stack.
+ - `closing` - Animated node representing whether the card is closing. `1` when closing, `0` if not.
+ - `layouts` - Layout measurements for various items we use for animation.
+ - `screen` - Layout of the whole screen. Contains `height` and `width` properties.
+
+ > **Note that when a screen is not the last, it will use the next screen's transition config.** This is because many transitions involve an animation of the previous screen, and so these two transitions need to be kept together to prevent running two different kinds of transitions on the two screens (for example a slide and a modal). You can check the `next` parameter to find out if you want to animate out the previous screen. For more information about this parameter, see [Animation](stack-navigator.md#animations) section.
+
+ A config which just fades the screen looks like this:
+
+ ```js
+ const forFade = ({ current }) => ({
+ cardStyle: {
+ opacity: current.progress,
+ },
+ });
+ ```
+
+ We can pass this function in `cardStyleInterpolator` option:
+
+ ```js name="Custom Card Style Interpolator" snack static2dynamic
+ import * as React from 'react';
+ import { Text, View } from 'react-native';
+ import {
+ createStaticNavigation,
+ useNavigation,
+ } from '@react-navigation/native';
+ import { Button } from '@react-navigation/elements';
+ import { createStackNavigator } from '@react-navigation/stack';
+
+ 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
+
+ );
+ }
+
+ // codeblock-focus-start
+ const forFade = ({ current }) => ({
+ cardStyle: {
+ opacity: current.progress,
+ },
+ });
+
+ const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ cardStyleInterpolator: forFade,
+ },
+ },
+ },
+ });
+ // codeblock-focus-end
+
+ const Navigation = createStaticNavigation(MyStack);
+
+ export default function App() {
+ return ;
+ }
+ ```
+
+The interpolator will be called for each screen. For example, say you have a 2 screens in the stack, A & B. B is the new screen coming into focus and A is the previous screen. The interpolator will be called for each screen:
+
+- The interpolator is called for `B`: Here, the `current.progress` value represents the progress of the transition, which will start at `0` and end at `1`. There won't be a `next.progress` since `B` is the last screen.
+- The interpolator is called for `A`: Here, the `current.progress` will stay at the value of `1` and won't change, since the current transition is running for `B`, not `A`. The `next.progress` value represents the progress of `B` and will start at `0` and end at `1`.
+
+Say we want to animate both screens during the transition. The easiest way to do it would be to combine the progress value of current and next screens:
+
+```js
+const progress = Animated.add(
+ current.progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 1],
+ extrapolate: 'clamp',
+ }),
+ next
+ ? next.progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 1],
+ extrapolate: 'clamp',
+ })
+ : 0
+);
+```
+
+Here, the screen `A` will have both `current.progress` and `next.progress`, and since `current.progress` stays at `1` and `next.progress` is changing, combined, the progress will change from `1` to `2`. The screen `B` will only have `current.progress` which will change from `0` to `1`. So, we can apply different interpolations for `0-1` and `1-2` to animate focused screen and unfocused screen respectively.
+
+A config which translates the previous screen slightly to the left, and translates the current screen from the right edge would look like this:
+
+```js
+const forSlide = ({ current, next, inverted, layouts: { screen } }) => {
+ const progress = Animated.add(
+ current.progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 1],
+ extrapolate: 'clamp',
+ }),
+ next
+ ? next.progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 1],
+ extrapolate: 'clamp',
+ })
+ : 0
+ );
+
+ return {
+ cardStyle: {
+ transform: [
+ {
+ translateX: Animated.multiply(
+ progress.interpolate({
+ inputRange: [0, 1, 2],
+ outputRange: [
+ screen.width, // Focused, but offscreen in the beginning
+ 0, // Fully focused
+ screen.width * -0.3, // Fully unfocused
+ ],
+ extrapolate: 'clamp',
+ }),
+ inverted
+ ),
+ },
+ ],
+ },
+ };
+};
+```
+
+- `headerStyleInterpolator` - This is a function which specifies interpolated styles for various parts of the header. It is expected to return at least empty object, possibly containing interpolated styles for left label and button, right button, title and background. Supported properties are:
+ - `leftLabelStyle` - Style for the label of the left button (back button label).
+ - `leftButtonStyle` - Style for the left button (usually the back button).
+ - `rightButtonStyle` - Style for the right button.
+ - `titleStyle` - Style for the header title text.
+ - `backgroundStyle` - Style for the header background.
+
+ The function receives the following properties in it's argument:
+ - `current` - Values for the current screen (the screen which owns this header).
+ - `progress` - Animated node representing the progress value of the current screen. `0` when screen should start coming into view, `0.5` when it's mid-way, `1` when it should be fully in view.
+ - `next` - Values for the screen after this one in the stack. This can be `undefined` in case the screen animating is the last one.
+ - `progress` - Animated node representing the progress value of the next screen.
+ - `layouts` - Layout measurements for various items we use for animation. Each layout object contain `height` and `width` properties.
+ - `screen` - Layout of the whole screen.
+ - `title` - Layout of the title element. Might be `undefined` when not rendering a title.
+ - `leftLabel` - Layout of the back button label. Might be `undefined` when not rendering a back button label.
+
+ A config that just fades the elements looks like this:
+
+ ```js
+ const forFade = ({ current, next }) => {
+ const opacity = Animated.add(
+ current.progress,
+ next ? next.progress : 0
+ ).interpolate({
+ inputRange: [0, 1, 2],
+ outputRange: [0, 1, 0],
+ });
+
+ return {
+ leftButtonStyle: { opacity },
+ rightButtonStyle: { opacity },
+ titleStyle: { opacity },
+ backgroundStyle: { opacity },
+ };
+ };
+ ```
+
+ We can pass this function in `headerStyleInterpolator` option:
+
+ ```js name="Custom Header Style Interpolator" snack static2dynamic
+ import * as React from 'react';
+ import { Text, View } from 'react-native';
+ import {
+ createStaticNavigation,
+ useNavigation,
+ } from '@react-navigation/native';
+ import { Button } from '@react-navigation/elements';
+ import { createStackNavigator } from '@react-navigation/stack';
+
+ 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
+
+ );
+ }
+
+ // codeblock-focus-start
+ const forFade = ({ current, next }) => {
+ const opacity = Animated.add(
+ current.progress,
+ next ? next.progress : 0
+ ).interpolate({
+ inputRange: [0, 1, 2],
+ outputRange: [0, 1, 0],
+ });
+
+ return {
+ leftButtonStyle: { opacity },
+ rightButtonStyle: { opacity },
+ titleStyle: { opacity },
+ backgroundStyle: { opacity },
+ };
+ };
+
+ const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ headerStyleInterpolator: forFade,
+ },
+ },
+ },
+ });
+ // codeblock-focus-end
+
+ const Navigation = createStaticNavigation(MyStack);
+
+ export default function App() {
+ return ;
+ }
+ ```
+
+### Pre-made configs
+
+With these options, it's possible to build custom transition animations for screens. We also export various configs from the library with ready-made animations which you can use:
+
+#### `TransitionSpecs`
+
+- `TransitionIOSSpec` - Exact values from UINavigationController's animation configuration.
+- `FadeInFromBottomAndroidSpec` - Configuration for activity open animation from Android Nougat.
+- `FadeOutToBottomAndroidSpec` - Configuration for activity close animation from Android Nougat.
+- `RevealFromBottomAndroidSpec` - Approximate configuration for activity open animation from Android Pie.
+
+Example:
+
+```js
+import { TransitionSpecs } from '@react-navigation/stack';
+
+// ...
+
+ ;
+```
+
+#### `CardStyleInterpolators`
+
+- `forHorizontalIOS` - Standard iOS-style slide in from the right.
+- `forVerticalIOS` - Standard iOS-style slide in from the bottom (used for modals).
+- `forModalPresentationIOS` - Standard iOS-style modal animation in iOS 13.
+- `forFadeFromBottomAndroid` - Standard Android-style fade in from the bottom for Android Oreo.
+- `forRevealFromBottomAndroid` - Standard Android-style reveal from the bottom for Android Pie.
+
+Example configuration for Android Oreo style vertical screen fade animation:
+
+```js name="Card Style Interpolators" snack static2dynamic
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import {
+ createStackNavigator,
+ CardStyleInterpolators,
+} from '@react-navigation/stack';
+// 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
+
+ );
+}
+
+// codeblock-focus-start
+const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ title: 'Profile',
+ cardStyleInterpolator: CardStyleInterpolators.forFadeFromBottomAndroid,
+ },
+ },
+ },
+});
+// codeblock-focus-end
+
+const Navigation = createStaticNavigation(MyStack);
+
+export default function App() {
+ return ;
+}
+```
+
+#### `HeaderStyleInterpolators`
+
+- `forUIKit` - Standard UIKit style animation for the header where the title fades into the back button label.
+- `forFade` - Simple fade animation for the header elements.
+- `forStatic` - Simple translate animation to translate the header along with the sliding screen.
+
+Example configuration for default iOS animation for header elements where the title fades into the back button:
+
+```js name="Header Style Interpolators" snack static2dynamic
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import {
+ createStackNavigator,
+ HeaderStyleInterpolators,
+} from '@react-navigation/stack';
+// 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
+
+ );
+}
+
+// codeblock-focus-start
+const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ title: 'Profile',
+ headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
+ },
+ },
+ },
+});
+// codeblock-focus-end
+
+const Navigation = createStaticNavigation(MyStack);
+
+export default function App() {
+ return ;
+}
+```
+
+:::warning
+
+Always define your animation configuration at the top-level of the file to ensure that the references don't change across re-renders. This is important for smooth and reliable transition animations.
+
+:::
+
+#### `TransitionPresets`
+
+We export various transition presets which bundle various set of these options together to match certain native animations. A transition preset is an object containing few animation related screen options exported under `TransitionPresets`. Currently the following presets are available:
+
+- `SlideFromRightIOS` - Standard iOS navigation transition.
+- `ModalSlideFromBottomIOS` - Standard iOS navigation transition for modals.
+- `ModalPresentationIOS` - Standard iOS modal presentation style (introduced in iOS 13).
+- `FadeFromBottomAndroid` - Standard Android navigation transition when opening or closing an Activity on Android < 9 (Oreo).
+- `RevealFromBottomAndroid` - Standard Android navigation transition when opening or closing an Activity on Android 9 (Pie).
+- `ScaleFromCenterAndroid` - Standard Android navigation transition when opening or closing an Activity on Android >= 10.
+- `DefaultTransition` - Default navigation transition for the current platform.
+- `ModalTransition` - Default modal transition for the current platform.
+
+You can spread these presets in `options` to customize the animation for a screen:
+
+```js name="Transition Presets - Modal Slide" snack static2dynamic
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import {
+ createStackNavigator,
+ TransitionPresets,
+} from '@react-navigation/stack';
+// 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
+
+ );
+}
+
+// codeblock-focus-start
+const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: {
+ screen: ProfileScreen,
+ options: {
+ title: 'Profile',
+ ...TransitionPresets.ModalSlideFromBottomIOS,
+ },
+ },
+ },
+});
+// codeblock-focus-end
+
+const Navigation = createStaticNavigation(MyStack);
+
+export default function App() {
+ return ;
+}
+```
+
+If you want to customize the transition animations for all of the screens in the navigator, you can specify it in `screenOptions` prop for the navigator.
+
+Example configuration for iOS modal presentation style:
+
+```js name="Transition Presets - Modal Presentation" snack static2dynamic
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import {
+ createStackNavigator,
+ TransitionPresets,
+} from '@react-navigation/stack';
+// 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
+
+ );
+}
+
+// codeblock-focus-start
+const MyStack = createStackNavigator({
+ initialRouteName: 'Home',
+ screenOptions: {
+ headerShown: false,
+ ...TransitionPresets.ModalPresentationIOS,
+ },
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+// codeblock-focus-end
+
+const Navigation = createStaticNavigation(MyStack);
+
+export default function App() {
+ return ;
+}
+```
+
+### Transparent modals
+
+A transparent modal is like a modal dialog which overlays the screen. The previous screen still stays visible underneath. To get a transparent modal screen, you can specify `presentation: 'transparentModal'` in the screen's options.
+
+Example:
+
+```js
+
+
+
+
+```
+
+Now, when you navigate to the `Modal` screen, it'll have a transparent background and the `Home` screen will be visible underneath.
+
+In addition to `presentation`, you might want to optionally specify few more things to get a modal dialog like behavior:
+
+- Disable the header with `headerShown: false`
+- Enable the overlay with `cardOverlayEnabled: true` (you can't tap the overlay to close the screen this way, see below for alternatives)
+
+If you want to further customize how the dialog animates, or want to close the screen when tapping the overlay etc., you can use the `useCardAnimation` hook to customize elements inside your screen.
+
+Example:
+
+```js
+import { Animated, View, Text, Pressable, StyleSheet } from 'react-native';
+import { useTheme, useNavigation } from '@react-navigation/native';
+import { useCardAnimation } from '@react-navigation/stack';
+import { Button } from '@react-navigation/elements';
+
+function ModalScreen() {
+ const navigation = useNavigation('Modal');
+ const { colors } = useTheme();
+ const { current } = useCardAnimation();
+
+ return (
+
+
+
+
+ Mise en place is a French term that literally means “put in place.” It
+ also refers to a way cooks in professional kitchens and restaurants
+ set up their work stations—first by gathering all ingredients for a
+ recipes, partially preparing them (like measuring out and chopping),
+ and setting them all near each other. Setting up mise en place before
+ cooking is another top tip for home cooks, as it seriously helps with
+ organization. It’ll pretty much guarantee you never forget to add an
+ ingredient and save you time from running back and forth from the
+ pantry ten times.
+
+
+ Okay
+
+
+
+ );
+}
+```
+
+Here we animate the scale of the dialog, and also add an overlay to close the dialog.
diff --git a/versioned_docs/version-8.x/state-persistence.md b/versioned_docs/version-8.x/state-persistence.md
new file mode 100755
index 00000000000..a2a5c6ab499
--- /dev/null
+++ b/versioned_docs/version-8.x/state-persistence.md
@@ -0,0 +1,314 @@
+---
+id: state-persistence
+title: State persistence
+sidebar_label: State persistence
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+You might want to save the user's location in the app, so that they are immediately returned to the same location after the app is restarted.
+
+This is especially valuable during development because it allows the developer to stay on the same screen when they refresh the app.
+
+## Usage
+
+To be able to persist the [navigation state](navigation-state.md), we can use the `onStateChange` and `initialState` props of the container.
+
+- `onStateChange` - This prop notifies us of any state changes. We can persist the state in this callback.
+- `initialState` - This prop allows us to pass an initial state to use for [navigation state](navigation-state.md). We can pass the restored state in this prop.
+
+
+
+
+```js name="Persisting the navigation state" snack dependencies=@react-native-async-storage/async-storage
+import * as React from 'react';
+// codeblock-focus-start
+import { Platform, View, Linking } from 'react-native';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import {
+ useNavigation,
+ createStaticNavigation,
+} from '@react-navigation/native';
+// codeblock-focus-end
+import { Button } from '@react-navigation/elements';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+
+function A() {
+ return ;
+}
+
+function B() {
+ const navigation = useNavigation('B');
+
+ return (
+
+ navigation.navigate('C')}>Go to C
+
+ );
+}
+
+function C() {
+ const navigation = useNavigation('C');
+
+ return (
+
+ navigation.navigate('D')}>Go to D
+
+ );
+}
+
+function D() {
+ return ;
+}
+
+const HomeStackScreen = createNativeStackNavigator({
+ screens: {
+ A: A,
+ },
+});
+
+const SettingsStackScreen = createNativeStackNavigator({
+ screens: {
+ B: B,
+ C: C,
+ D: D,
+ },
+});
+
+const Tab = createBottomTabNavigator({
+ screens: {
+ Home: {
+ screen: HomeStackScreen,
+ options: {
+ headerShown: false,
+ tabBarLabel: 'Home!',
+ },
+ },
+ Settings: {
+ screen: SettingsStackScreen,
+ options: {
+ headerShown: false,
+ tabBarLabel: 'Settings!',
+ },
+ },
+ },
+});
+
+const Navigation = createStaticNavigation(Tab);
+
+// codeblock-focus-start
+
+const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1';
+
+export default function App() {
+ const [isReady, setIsReady] = React.useState(Platform.OS === 'web'); // Don't persist state on web since it's based on URL
+ const [initialState, setInitialState] = React.useState();
+
+ React.useEffect(() => {
+ const restoreState = async () => {
+ try {
+ const initialUrl = await Linking.getInitialURL();
+
+ if (Platform.OS !== 'web' && initialUrl == null) {
+ const savedState = await AsyncStorage.getItem(PERSISTENCE_KEY);
+ const state = savedState ? JSON.parse(savedState) : undefined;
+
+ if (state !== undefined) {
+ setInitialState(state);
+ }
+ }
+ } finally {
+ setIsReady(true);
+ }
+ };
+
+ if (!isReady) {
+ restoreState();
+ }
+ }, [isReady]);
+
+ if (!isReady) {
+ return null;
+ }
+
+ return (
+
+ AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
+ }
+ />
+ );
+}
+// codeblock-focus-end
+```
+
+
+
+
+```js name="Persisting the navigation state" snack dependencies=@react-native-async-storage/async-storage
+import * as React from 'react';
+// codeblock-focus-start
+import { Platform, View, Linking } from 'react-native';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import { NavigationContainer, useNavigation } from '@react-navigation/native';
+// codeblock-focus-end
+import { Button } from '@react-navigation/elements';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+
+const Tab = createBottomTabNavigator();
+const HomeStack = createNativeStackNavigator();
+const SettingsStack = createNativeStackNavigator();
+
+function A() {
+ return ;
+}
+
+function B() {
+ const navigation = useNavigation('B');
+
+ return (
+
+ navigation.navigate('C')}>Go to C
+
+ );
+}
+
+function C() {
+ const navigation = useNavigation('C');
+
+ return (
+
+ navigation.navigate('D')}>Go to D
+
+ );
+}
+
+function D() {
+ return ;
+}
+
+function HomeStackScreen() {
+ return (
+
+
+
+ );
+}
+
+function SettingsStackScreen() {
+ return (
+
+
+
+
+
+ );
+}
+
+function RootTabs() {
+ return (
+
+
+
+
+ );
+}
+
+// codeblock-focus-start
+
+const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1';
+
+export default function App() {
+ const [isReady, setIsReady] = React.useState(Platform.OS === 'web'); // Don't persist state on web since it's based on URL
+ const [initialState, setInitialState] = React.useState();
+
+ React.useEffect(() => {
+ const restoreState = async () => {
+ try {
+ const initialUrl = await Linking.getInitialURL();
+
+ if (initialUrl == null) {
+ // Only restore state if there's no deep link
+ const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY);
+ const state = savedStateString
+ ? JSON.parse(savedStateString)
+ : undefined;
+
+ if (state !== undefined) {
+ setInitialState(state);
+ }
+ }
+ } finally {
+ setIsReady(true);
+ }
+ };
+
+ if (!isReady) {
+ restoreState();
+ }
+ }, [isReady]);
+
+ if (!isReady) {
+ return null;
+ }
+
+ return (
+
+ AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
+ }
+ >
+
+
+ );
+}
+// codeblock-focus-end
+```
+
+
+
+
+:::warning
+
+It is recommended to use an [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) in your app and clear the persisted state if an error occurs. This will ensure that the app doesn't get stuck in an error state if a screen crashes.
+
+:::
+
+### Development Mode
+
+This feature is particularly useful in development mode. You can enable it selectively using the following approach:
+
+```js
+const [isReady, setIsReady] = React.useState(__DEV__ ? false : true);
+```
+
+While it can be used for production as well, use it with caution as it can make the app unusable if the app is crashing on a particular screen - as the user will still be on the same screen after restarting. So if you are using it in production, make sure to clear the persisted state if an error occurs.
+
+### Loading View
+
+Because the state is restored asynchronously, the app must render an empty/loading view for a moment before we have the initial state. To handle this, we can return a loading view when `isReady` is `false`:
+
+```js
+if (!isReady) {
+ return ;
+}
+```
+
+## Warning: Serializable State
+
+Each param, route, and navigation state must be fully serializable for this feature to work. Typically, you would serialize the state as a JSON string. This means that your routes and params must contain no functions, class instances, or recursive data structures. React Navigation already [warns you during development](troubleshooting.md#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state) if it encounters non-serializable data, so watch out for the warning if you plan to persist navigation state.
+
+You can modify the initial state object before passing it to container, but note that if your `initialState` isn't a [valid navigation state](navigation-state.md#stale-state-objects), React Navigation may not be able to handle the situation gracefully in some scenarios.
diff --git a/versioned_docs/version-8.x/static-configuration.md b/versioned_docs/version-8.x/static-configuration.md
new file mode 100644
index 00000000000..c71211f50af
--- /dev/null
+++ b/versioned_docs/version-8.x/static-configuration.md
@@ -0,0 +1,296 @@
+---
+id: static-configuration
+title: Static configuration
+sidebar_label: Static configuration
+---
+
+The bulk of the static configuration is done using the `createXNavigator` functions, e.g. [`createNativeStackNavigator`](native-stack-navigator.md), [`createBottomTabNavigator`](bottom-tab-navigator.md), [`createDrawerNavigator`](drawer-navigator.md) etc. We'll refer to these functions as `createXNavigator` in the rest of this guide.
+
+## `createXNavigator`
+
+The `createXNavigator` functions take one argument, which is an object with the following properties:
+
+- Same props as the navigator component, e.g. `id`, `initialRouteName`, `screenOptions` etc. See [Navigator](navigator.md) as well as the docs for each navigator for more details on the props they accept.
+- `screens` - an object containing configuration for each screen in the navigator.
+- `groups` - an optional object containing groups of screens (equivalent to [`Group`](group.md) in the dynamic API).
+
+For example:
+
+```js
+const RootStack = createNativeStackNavigator({
+ initialRouteName: 'Home',
+ screenOptions: {
+ headerTintColor: 'white',
+ headerStyle: {
+ backgroundColor: 'tomato',
+ },
+ },
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+```
+
+### `screens`
+
+The `screens` object can contain key value pairs where the key is the name of the screen and the value can be several things:
+
+- A component to render:
+
+ ```js
+ const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ },
+ });
+ ```
+
+- A navigator configured using `createXNavigator` for nested navigators:
+
+ ```js
+ const HomeTabs = createBottomTabNavigator({
+ screens: {
+ Groups: GroupsScreen,
+ Chats: ChatsScreen,
+ },
+ });
+
+ const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeTabs,
+ },
+ });
+ ```
+
+- An object containing configuration for the screen. This configuration contains the various properties:
+
+ ```js
+ const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: {
+ screen: HomeScreen,
+ linking: {
+ path: 'home',
+ },
+ },
+ },
+ });
+ ```
+
+ See [Screen configuration](#screen-configuration) for more details.
+
+### `groups`
+
+The `groups` object can contain key-value pairs where the key is the name of the group and the value is the group configuration.
+
+The configuration object for a screen accepts the [properties described in the Group page](group.md). In addition, the following properties are available when using static configuration:
+
+- `if` - this can be used to conditionally render the group and works the same as the [`if` property in the screen configuration](#if).
+- `screens` - an object containing configuration for each screen in the group. The configuration is the same as the [`screens` object in the navigator configuration](#screens).
+
+Example:
+
+```js
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+ groups: {
+ Guest: {
+ if: useIsGuest,
+ screenOptions: {
+ headerShown: false,
+ },
+ screens: {
+ // ...
+ },
+ },
+ User: {
+ if: useIsUser,
+ screens: {
+ // ...
+ },
+ },
+ },
+});
+```
+
+### Screen configuration
+
+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:
+
+```js
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Profile: {
+ screen: ProfileScreen,
+ linking: {
+ path: 'u/:userId',
+ parse: {
+ userId: (id) => id.replace(/^@/, ''),
+ },
+ stringify: {
+ userId: (id) => `@${id}`,
+ },
+ },
+ },
+ Chat: {
+ screen: ChatScreen,
+ linking: 'chat/:chatId',
+ },
+ },
+});
+```
+
+The `linking` object supports the same configuration options described in [Configuring links](configuring-links.md) such as `parse`, `stringify` and `exact`.
+
+To make deep links work on native apps, you also need to [configure your app](deep-linking.md) and pass `prefixes` to the navigation component returned by [`createStaticNavigation`](static-configuration.md#createstaticnavigation):
+
+```js
+const Navigation = createStaticNavigation(RootStack);
+
+const linking = {
+ prefixes: ['https://example.com', 'example://'],
+};
+
+function App() {
+ return ;
+}
+```
+
+#### `if`
+
+Callback to determine whether the screen should be rendered or not. It doesn't receive any arguments. This can be useful for conditional rendering of screens, e.g. - if you want to render a different screen for logged in users.
+
+You can use a custom hook to use custom logic to determine the return value:
+
+```js
+const useIsLoggedIn = () => {
+ const { isLoggedIn } = React.useContext(AuthContext);
+
+ return isLoggedIn;
+};
+
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: {
+ screen: HomeScreen,
+ if: useIsLoggedIn,
+ },
+ },
+});
+```
+
+The above example will only render the `HomeScreen` if the user is logged in.
+
+For more details, see [Authentication flow](auth-flow.md?config=static).
+
+## `createStaticNavigation`
+
+The `createStaticNavigation` function takes the static config returned by `createXNavigator` functions and returns a React component to render:
+
+```js
+const Navigation = createStaticNavigation(RootStack);
+
+function App() {
+ return ;
+}
+```
+
+This component is a wrapper around the `NavigationContainer` component and accepts the [same props and ref as the `NavigationContainer`](navigation-container.md) component. It is intended to be rendered once at the root of your app similar to how you'd use `NavigationContainer` component.
+
+### Differences in the `linking` prop
+
+Similar to `NavigationContainer`, the component returned by `createStaticNavigation` also accepts a [`linking`](navigation-container.md#linking) prop. However, there are some key differences:
+
+1. It's not possible to pass a full `config` object to the `linking` prop. It can only accept [`path`](configuring-links.md#apps-under-subpaths) and an [`initialRouteName` for the root navigator](configuring-links.md#rendering-an-initial-route).
+2. The linking config is collected from the [`linking`](#linking) properties specified in the screen configuration.
+3. It's possible to pass `enabled: 'auto'` to automatically generate paths for all leaf screens:
+
+ ```js
+ const Navigation = createStaticNavigation(RootStack);
+
+ const linking = {
+ enabled: 'auto',
+ prefixes: ['https://example.com', 'example://'],
+ };
+
+ function App() {
+ return ;
+ }
+ ```
+
+ See [How does automatic path generation work](configuring-links.md#how-does-automatic-path-generation-work) for more details.
+
+## `createComponentForStaticNavigation`
+
+The `createComponentForStaticNavigation` function takes the static config returned by `createXNavigator` functions and returns a React component to render. The second argument is a name for the component that'd be used in React DevTools:
+
+```js
+const RootStackNavigator = createComponentForStaticNavigation(
+ RootStack,
+ 'RootNavigator'
+);
+```
+
+The returned component doesn't take any props. All of the configuration is inferred from the static config. It's essentially the same as defining a component using the dynamic API.
+
+This looks similar to `createStaticNavigation` however they are very different. When using static configuration, you'd never use this function directly. The only time you'd use this is if you're migrating away from static configuration and want to reuse existing code you wrote instead of rewriting it to the dynamic API. See [Combining static and dynamic APIs](combine-static-with-dynamic.md) for more details.
+
+## `createPathConfigForStaticNavigation`
+
+The `createPathConfigForStaticNavigation` function takes the static config returned by `createXNavigator` functions and returns a path config object that can be used within the linking config.
+
+```js
+const config = {
+ screens: {
+ Home: {
+ screens: createPathConfigForStaticNavigation(HomeTabs),
+ },
+ },
+};
+```
+
+Similar to `createComponentForStaticNavigation`, this is intended to be used when migrating away from static configuration. See [Combining static and dynamic APIs](combine-static-with-dynamic.md) for more details.
diff --git a/versioned_docs/version-8.x/status-bar.md b/versioned_docs/version-8.x/status-bar.md
new file mode 100755
index 00000000000..ee5c2498143
--- /dev/null
+++ b/versioned_docs/version-8.x/status-bar.md
@@ -0,0 +1,453 @@
+---
+id: status-bar
+title: Different status bar configuration based on route
+sidebar_label: Status bar configuration
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+If you don't have a navigation header, or your navigation header changes color based on the route, you'll want to ensure that the correct color is used for the content.
+
+## Stack
+
+This is a simple task when using a stack. You can render the `StatusBar` component, which is exposed by React Native, and set your config.
+
+
+
+
+```js name="Different status bar" snack
+import * as React from 'react';
+import { View, Text, StatusBar, StyleSheet } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+
+function Screen1() {
+ const navigation = useNavigation('Screen1');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ // highlight-start
+
+ // highlight-end
+ Light Screen
+ navigation.navigate('Screen2')}>
+ Next screen
+
+
+ );
+}
+
+function Screen2() {
+ const navigation = useNavigation('Screen2');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ // highlight-start
+
+ // highlight-end
+ Dark Screen
+ navigation.navigate('Screen1')}>
+ Next screen
+
+
+ );
+}
+
+const RootStack = createNativeStackNavigator({
+ screenOptions: {
+ headerShown: false,
+ },
+ screens: {
+ Screen1: Screen1,
+ Screen2: Screen2,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
+});
+```
+
+
+
+
+
+```js name="Different status bar" snack
+import * as React from 'react';
+import { View, Text, StatusBar, StyleSheet } from 'react-native';
+import { NavigationContainer, useNavigation } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+import {
+ SafeAreaProvider,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context';
+
+function Screen1() {
+ const navigation = useNavigation('Screen1');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ // highlight-start
+
+ // highlight-end
+ Light Screen
+ navigation.navigate('Screen2')}>
+ Next screen
+
+
+ );
+}
+
+function Screen2() {
+ const navigation = useNavigation('Screen2');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ // highlight-start
+
+ // highlight-end
+ Dark Screen
+ navigation.navigate('Screen1')}>
+ Next screen
+
+
+ );
+}
+
+const Stack = createNativeStackNavigator();
+
+export default function App() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
+```
+
+
+
+
+
+
+
+
+
+
+
+
+## Tabs and Drawer
+
+If you're using a tab or drawer navigator, it's a bit more complex because all of the screens in the navigator might be rendered at once and kept rendered - that means that the last `StatusBar` config you set will be used (likely on the final tab of your tab navigator, not what the user is seeing).
+
+To fix this, we'll have to do make the status bar component aware of screen focus and render it only when the screen is focused. We can achieve this by using the [`useIsFocused` hook](use-is-focused.md) and creating a wrapper component:
+
+```js
+import * as React from 'react';
+import { StatusBar } from 'react-native';
+import { useIsFocused } from '@react-navigation/native';
+
+function FocusAwareStatusBar(props) {
+ const isFocused = useIsFocused();
+
+ return isFocused ? : null;
+}
+```
+
+Now, our screens (both `Screen1.js` and `Screen2.js`) will use the `FocusAwareStatusBar` component instead of the `StatusBar` component from React Native:
+
+
+
+
+```js name="Different status bar based on tabs" snack
+import * as React from 'react';
+import { View, Text, StatusBar, StyleSheet } from 'react-native';
+import { useIsFocused } from '@react-navigation/native';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+
+function FocusAwareStatusBar(props) {
+ const isFocused = useIsFocused();
+
+ return isFocused ? : null;
+}
+
+// codeblock-focus-start
+function Screen1() {
+ const navigation = useNavigation('Screen1');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+
+ Light Screen
+ navigation.navigate('Screen2')}>
+ Next screen
+
+
+ );
+}
+
+function Screen2() {
+ const navigation = useNavigation('Screen2');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+
+ Dark Screen
+ navigation.navigate('Screen1')}>
+ Next screen
+
+
+ );
+}
+// codeblock-focus-end
+
+const RootStack = createNativeStackNavigator({
+ screenOptions: {
+ headerShown: false,
+ },
+ screens: {
+ Screen1: Screen1,
+ Screen2: Screen2,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
+```
+
+
+
+
+```js name="Different status bar based on tabs" snack
+import * as React from 'react';
+import { View, Text, StatusBar, StyleSheet } from 'react-native';
+import { useIsFocused } from '@react-navigation/native';
+import { NavigationContainer, useNavigation } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { Button } from '@react-navigation/elements';
+import {
+ SafeAreaProvider,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context';
+
+function FocusAwareStatusBar(props) {
+ const isFocused = useIsFocused();
+
+ return isFocused ? : null;
+}
+
+// codeblock-focus-start
+function Screen1() {
+ const navigation = useNavigation('Screen1');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+
+ Light Screen
+ navigation.navigate('Screen2')}>
+ Next screen
+
+
+ );
+}
+
+function Screen2() {
+ const navigation = useNavigation('Screen2');
+ const insets = useSafeAreaInsets();
+
+ return (
+
+
+ Dark Screen
+ navigation.navigate('Screen1')}>
+ Next screen
+
+
+ );
+}
+// codeblock-focus-end
+
+const Stack = createNativeStackNavigator();
+
+export default function App() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
+```
+
+
+
+
+Although not necessary, you can use the `FocusAwareStatusBar` component in the screens of the native stack navigator as well.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/versioned_docs/version-8.x/tab-actions.md b/versioned_docs/version-8.x/tab-actions.md
new file mode 100755
index 00000000000..0944a0ec620
--- /dev/null
+++ b/versioned_docs/version-8.x/tab-actions.md
@@ -0,0 +1,75 @@
+---
+id: tab-actions
+title: TabActions reference
+sidebar_label: TabActions
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+`TabActions` is an object containing methods for generating actions specific to tab-based navigators. Its methods expand upon the actions available in [`CommonActions`](navigation-actions.md).
+
+The following actions are supported:
+
+## jumpTo
+
+The `jumpTo` action can be used to jump to an existing route in the tab navigator.
+
+- `name` - _string_ - Name of the route to jump to.
+- `params` - _object_ - Screen params to pass to the destination route.
+
+```js name="Tab Actions - jumpTo" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+ TabActions,
+} from '@react-navigation/native';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+
+// codeblock-focus-start
+function HomeScreen() {
+ const navigation = useNavigation();
+ // highlight-next-line
+ const jumpToAction = TabActions.jumpTo('Profile', { user: 'Satya' });
+
+ return (
+
+ Home!
+ {
+ // highlight-next-line
+ navigation.dispatch(jumpToAction);
+ }}
+ >
+ Jump to Profile
+
+
+ );
+}
+// codeblock-focus-end
+
+function ProfileScreen({ route }) {
+ return (
+
+ Profile!
+ {route?.params?.user ? route.params.user : 'Noone'}'s profile
+
+ );
+}
+
+const MyTabs = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTabs);
+
+export default function App() {
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/tab-view.md b/versioned_docs/version-8.x/tab-view.md
new file mode 100644
index 00000000000..2e11ed98084
--- /dev/null
+++ b/versioned_docs/version-8.x/tab-view.md
@@ -0,0 +1,738 @@
+---
+id: tab-view
+title: React Native Tab View
+sidebar_label: Tab View
+---
+
+React Native Tab View is a cross-platform Tab View component for React Native implemented using [`react-native-pager-view`](https://github.com/callstack/react-native-viewpager) on Android & iOS, and [PanResponder](https://reactnative.dev/docs/panresponder) on Web, macOS, and Windows.
+
+It follows material design guidelines by default, but you can also use your own custom tab bar or position the tab bar at the bottom.
+
+
+
+
+
+This package doesn't integrate with React Navigation. If you want to integrate the tab view with React Navigation's navigation system, e.g. want to show screens in the tab bar and be able to navigate between them using `navigation.navigate` etc, use [Material Top Tab Navigator](material-top-tab-navigator.md) instead.
+
+## Installation
+
+To use this package, open a Terminal in the project root and run:
+
+```bash npm2yarn
+npm install react-native-tab-view
+```
+
+The library depends on [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view) for rendering the pages.
+
+
+
+
+If you have a Expo managed project, in your project directory, run:
+
+```bash
+npx expo install react-native-pager-view
+```
+
+
+
+
+If you have a bare React Native project, in your project directory, run:
+
+```bash npm2yarn
+npm install react-native-pager-view
+```
+
+
+
+
+If you're on a Mac and developing for iOS, you also need to install [pods](https://cocoapods.org/) to complete the linking.
+
+```bash
+npx pod-install ios
+```
+
+## Quick start
+
+```js name="React Native Tab View" snack
+// codeblock-focus-start
+import * as React from 'react';
+import { View, useWindowDimensions } from 'react-native';
+import { TabView, SceneMap } from 'react-native-tab-view';
+
+// codeblock-focus-end
+const FirstRoute = () => (
+
+);
+
+const SecondRoute = () => (
+
+);
+
+// codeblock-focus-start
+const renderScene = SceneMap({
+ first: FirstRoute,
+ second: SecondRoute,
+});
+
+const routes = [
+ { key: 'first', title: 'First' },
+ { key: 'second', title: 'Second' },
+];
+
+export default function TabViewExample() {
+ const layout = useWindowDimensions();
+ const [index, setIndex] = React.useState(0);
+
+ return (
+
+ );
+}
+// codeblock-focus-end
+```
+
+## More examples on Snack
+
+- [Custom Tab Bar](https://snack.expo.io/@satya164/react-native-tab-view-custom-tabbar)
+- [Lazy Load](https://snack.expo.io/@satya164/react-native-tab-view-lazy-load)
+
+## API reference
+
+The package exports a `TabView` component which is the one you'd use to render the tab view, and a `TabBar` component which is the default tab bar implementation.
+
+### `TabView`
+
+Container component responsible for rendering and managing tabs. Follows material design styles by default.
+
+Basic usage look like this:
+
+```js
+
+```
+
+#### TabView Props
+
+##### `navigationState` (`required`)
+
+State for the tab view. The state should contain the following properties:
+
+- `index`: a number representing the index of the active route in the `routes` array
+- `routes`: an array containing a list of route objects used for rendering the tabs
+
+Each route object should contain the following properties:
+
+- `key`: a unique key to identify the route (required)
+- `title`: title for the route to display in the tab bar
+- `icon`: icon for the route to display in the tab bar
+- `accessibilityLabel`: accessibility label for the tab button
+- `testID`: test id for the tab button
+
+Example:
+
+```js
+{
+ index: 1,
+ routes: [
+ { key: 'music', title: 'Music' },
+ { key: 'albums', title: 'Albums' },
+ { key: 'recents', title: 'Recents' },
+ { key: 'purchased', title: 'Purchased' },
+ ]
+}
+```
+
+`TabView` is a controlled component, which means the `index` needs to be updated via the `onIndexChange` callback.
+
+##### `onIndexChange` (`required`)
+
+Callback which is called on tab change, receives the index of the new tab as argument.
+The navigation state needs to be updated when it's called, otherwise the change is dropped.
+
+##### `renderScene` (`required`)
+
+Callback which returns a react element to render as the page for the tab. Receives an object containing the route as the argument:
+
+```js
+const renderScene = ({ route, jumpTo }) => {
+ switch (route.key) {
+ case 'music':
+ return ;
+ case 'albums':
+ return ;
+ }
+};
+```
+
+You need to make sure that your individual routes implement a `shouldComponentUpdate` to improve the performance. To make it easier to specify the components, you can use the `SceneMap` helper.
+
+`SceneMap` takes an object with the mapping of `route.key` to React components and returns a function to use with `renderScene` prop.
+
+```js
+import { SceneMap } from 'react-native-tab-view';
+
+...
+
+const renderScene = SceneMap({
+ music: MusicRoute,
+ albums: AlbumsRoute,
+});
+```
+
+Specifying the components this way is easier and takes care of implementing a `shouldComponentUpdate` method.
+
+Each scene receives the following props:
+
+- `route`: the current route rendered by the component
+- `jumpTo`: method to jump to other tabs, takes a `route.key` as it's argument
+- `position`: animated node which represents the current position
+
+The `jumpTo` method can be used to navigate to other tabs programmatically:
+
+```js
+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`.
+
+:::warning
+
+**Do not** pass inline functions to `SceneMap`, for example, don't do the following:
+
+```js
+SceneMap({
+ first: () => ,
+ second: SecondRoute,
+});
+```
+
+:::
+
+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:
+
+```js
+const renderScene = ({ route }) => {
+ switch (route.key) {
+ case 'first':
+ return ;
+ case 'second':
+ return ;
+ default:
+ return null;
+ }
+};
+```
+
+##### `renderTabBar`
+
+Callback which returns a custom React Element to use as the tab bar:
+
+```js
+import { TabBar } from 'react-native-tab-view';
+
+...
+
+ }
+ ...
+/>
+```
+
+If this is not specified, the default tab bar is rendered. You pass this props to customize the default tab bar, provide your own tab bar, or disable the tab bar completely.
+
+```js
+ null}
+ ...
+/>
+```
+
+##### `tabBarPosition`
+
+Position of the tab bar in the tab view. Possible values are `'top'` and `'bottom'`. Defaults to `'top'`.
+
+##### `lazy`
+
+Function which takes an object with the current route and returns a boolean to indicate whether to lazily render the scenes.
+
+By default all scenes are rendered to provide a smoother swipe experience. But you might want to defer the rendering of unfocused scenes until the user sees them. To enable lazy rendering for a particular scene, return `true` from `lazy` for that `route`:
+
+```js
+ route.name === 'Albums'}
+ ...
+/>
+```
+
+When you enable lazy rendering for a screen, it will usually take some time to render when it comes into focus. You can use the `renderLazyPlaceholder` prop to customize what the user sees during this short period.
+
+You can also pass a boolean to enable lazy for all of the scenes:
+
+```js
+
+```
+
+##### `lazyPreloadDistance`
+
+When `lazy` is enabled, you can specify how many adjacent routes should be preloaded with this prop. This value defaults to `0` which means lazy pages are loaded as they come into the viewport.
+
+##### `renderLazyPlaceholder`
+
+Callback which returns a custom React Element to render for routes that haven't been rendered yet. Receives an object containing the route as the argument. The `lazy` prop also needs to be enabled.
+
+This view is usually only shown for a split second. Keep it lightweight.
+
+By default, this renders `null`.
+
+##### `keyboardDismissMode`
+
+String indicating whether the keyboard gets dismissed in response to a drag gesture. Possible values are:
+
+- `'auto'` (default): the keyboard is dismissed when the index changes.
+- `'on-drag'`: the keyboard is dismissed when a drag begins.
+- `'none'`: drags do not dismiss the keyboard.
+
+##### `swipeEnabled`
+
+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.
+
+##### `onSwipeStart`
+
+Callback which is called when the swipe gesture starts, i.e. the user touches the screen and moves it.
+
+##### `onSwipeEnd`
+
+Callback which is called when the swipe gesture ends, i.e. the user lifts their finger from the screen after the swipe gesture.
+
+##### `initialLayout`
+
+Object containing the initial height and width of the screens. Passing this will improve the initial rendering performance. For most apps, this is a good default:
+
+```js
+
+```
+
+##### `overScrollMode`
+
+Used to override default value of pager's overScroll mode. Can be `auto`, `always` or `never` (Android only).
+
+##### `pagerStyle`
+
+Style to apply to the pager view wrapping all the scenes.
+
+##### `style`
+
+Style to apply to the tab view container.
+
+### `TabBar`
+
+Material design themed tab bar. To customize the tab bar, you'd need to use the `renderTabBar` prop of `TabView` to render the `TabBar` and pass additional props.
+
+For example, to customize the indicator color and the tab bar background color, you can pass `indicatorStyle` and `style` props to the `TabBar` respectively:
+
+```js
+const renderTabBar = props => (
+
+);
+
+//...
+
+
+return (
+
+);
+```
+
+#### TabBar Props
+
+##### `renderTabBarItem`
+
+Function which takes a `TabBarItemProps` object and returns a custom React Element to be used as a tab button.
+
+##### `renderIndicator`
+
+Function which takes an object with the current route and returns a custom React Element to be used as a tab indicator.
+
+##### `onTabPress`
+
+Function to execute on tab press. It receives the scene for the pressed tab, useful for things like scroll to top.
+
+By default, tab press also switches the tab. To prevent this behavior, you can call `preventDefault`:
+
+```js
+ {
+ if (route.key === 'home') {
+ preventDefault();
+
+ // Do something else
+ }
+ }}
+ ...
+/>
+```
+
+##### `onTabLongPress`
+
+Function to execute on tab long press, use for things like showing a menu with more options
+
+##### `activeColor`
+
+Custom color for icon and label in the active tab.
+
+##### `inactiveColor`
+
+Custom color for icon and label in the inactive tab.
+
+##### `pressColor`
+
+Color for material ripple (Android >= 5.0 only).
+
+##### `pressOpacity`
+
+Opacity for pressed tab (iOS and Android < 5.0 only).
+
+##### `scrollEnabled`
+
+Boolean indicating whether to make the tab bar scrollable.
+
+If you set `scrollEnabled` to `true`, you should also specify a `width` in `tabStyle` to improve the initial render.
+
+##### `bounces`
+
+Boolean indicating whether the tab bar bounces when scrolling.
+
+##### `tabStyle`
+
+Style to apply to the individual tab items in the tab bar.
+
+By default, all tab items take up the same pre-calculated width based on the width of the container. If you want them to take their original width, you can specify `width: 'auto'` in `tabStyle`.
+
+##### `indicatorStyle`
+
+Style to apply to the active indicator.
+
+##### `indicatorContainerStyle`
+
+Style to apply to the container view for the indicator.
+
+##### `contentContainerStyle`
+
+Style to apply to the inner container for tabs.
+
+##### `style` (`TabBar`)
+
+Style to apply to the tab bar container.
+
+##### `gap`
+
+Spacing between the tab items.
+
+##### `testID` (`TabBar`)
+
+Test ID for the tab bar. Can be used for scrolling the tab bar in tests
+
+#### Options
+
+Options describe how each tab should be configured. There are 2 ways to specify options:
+
+- `commonOptions`: Options that apply to all tabs.
+- `options`: Options that apply to specific tabs. It has the route key as the key and the object with options.
+
+Example:
+
+```js
+ (
+
+ ),
+ }}
+ options={{
+ albums: {
+ labelText: 'Albums',
+ },
+ profile: {
+ labelText: 'Profile',
+ },
+ }}
+/>
+```
+
+The following options are available:
+
+##### `accessibilityLabel`
+
+Accessibility label for the tab button. Uses `route.accessibilityLabel` by default if specified, otherwise uses the route title.
+
+##### `accessible`
+
+Whether to mark the tab as `accessible`. Defaults to `true`.
+
+##### `testID`
+
+Test ID for the tab button. Uses `route.testID` by default.
+
+##### `labelText`
+
+Label text for the tab button. Uses `route.title` by default.
+
+##### `labelAllowFontScaling`
+
+Whether label font should scale to respect Text Size accessibility settings. Defaults to `true`.
+
+##### `href`
+
+URL to use for the anchor tag for the tab button on the Web.
+
+##### `label`
+
+A function that returns a custom React Element to be used as a label. The function receives an object with the following properties:
+
+- `route` - The route object for the tab.
+- `labelText` - The label text for the tab specified in the `labelText` option or the `route title`.
+- `focused` - Whether the label is for the focused state.
+- `color` - The color of the label.
+- `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings.
+- `style` - The style object for the label.
+
+```js
+label: ({ route, labelText, focused, color }) => (
+ {labelText ?? route.name}
+);
+```
+
+##### `labelStyle`
+
+Style to apply to the tab item label.
+
+##### `icon`
+
+A function that returns a custom React Element to be used as an icon. The function receives an object with the following properties:
+
+- `route` - The route object for the tab.
+- `focused` - Whether the icon is for the focused state.
+- `color` - The color of the icon.
+- `size` - The size of the icon.
+
+```js
+icon: ({ route, focused, color }) => (
+
+);
+```
+
+##### `badge`
+
+A function that returns a custom React Element to be used as a badge. The function receives an object with the following properties:
+
+- `route` - The route object for the tab.
+
+```js
+badge: ({ route }) => (
+
+);
+```
+
+##### `sceneStyle`
+
+Style to apply to the view wrapping each screen. You can pass this to override some default styles such as overflow clipping.
+
+## Optimization Tips
+
+### Avoid unnecessary re-renders
+
+The `renderScene` function is called every time the index changes. If your `renderScene` function is expensive, it's good idea move each route to a separate component if they don't depend on the index, and use `shouldComponentUpdate` or `React.memo` in your route components to prevent unnecessary re-renders.
+
+For example, instead of:
+
+```js
+const renderScene = ({ route }) => {
+ switch (route.key) {
+ case 'home':
+ return (
+
+
+
+
+ );
+ default:
+ return null;
+ }
+};
+```
+
+Do the following:
+
+```js
+const renderScene = ({ route }) => {
+ switch (route.key) {
+ case 'home':
+ return ;
+ default:
+ return null;
+ }
+};
+```
+
+Where ` ` is a `PureComponent` if you're using class components:
+
+```js
+export default class HomeComponent extends React.PureComponent {
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
+```
+
+Or, wrapped in `React.memo` if you're using function components:
+
+```js
+function HomeComponent() {
+ return (
+
+
+
+
+ );
+}
+
+export default React.memo(HomeComponent);
+```
+
+### Avoid one frame delay
+
+We need to measure the width of the container and hence need to wait before rendering some elements on the screen. If you know the initial width upfront, you can pass it in and we won't need to wait for measuring it. Most of the time, it's just the window width.
+
+For example, pass the following `initialLayout` to `TabView`:
+
+```js
+const initialLayout = {
+ height: 0,
+ width: Dimensions.get('window').width,
+};
+```
+
+The tab view will still react to changes in the dimension and adjust accordingly to accommodate things like orientation change.
+
+### Optimize large number of routes
+
+If you've a large number of routes, especially images, it can slow the animation down a lot. You can instead render a limited number of routes.
+
+For example, do the following to render only 2 routes on each side:
+
+```js
+const renderScene = ({ route }) => {
+ if (Math.abs(index - routes.indexOf(route)) > 2) {
+ return ;
+ }
+
+ return ;
+};
+```
+
+### Avoid rendering TabView inside ScrollView
+
+Nesting the `TabView` inside a vertical `ScrollView` will disable the optimizations in the `FlatList` components rendered inside the `TabView`. So avoid doing it if possible.
+
+### Use `lazy` and `renderLazyPlaceholder` props to render routes as needed
+
+The `lazy` option is disabled by default to provide a smoother tab switching experience, but you can enable it and provide a placeholder component for a better lazy loading experience. Enabling `lazy` can improve initial load performance by rendering routes only when they come into view. Refer the [prop reference](#lazy) for more details.
diff --git a/versioned_docs/version-8.x/testing.md b/versioned_docs/version-8.x/testing.md
new file mode 100644
index 00000000000..a120a33f665
--- /dev/null
+++ b/versioned_docs/version-8.x/testing.md
@@ -0,0 +1,957 @@
+---
+id: testing
+title: Writing tests
+sidebar_label: Writing tests
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+React Navigation components can be tested in a similar way to other React components. This guide will cover how to write tests for components using React Navigation using [Jest](https://jestjs.io).
+
+## Guiding principles
+
+When writing tests, it's encouraged to write tests that closely resemble how users interact with your app. Keeping this in mind, here are some guiding principles to follow:
+
+- **Test the result, not the action**: Instead of checking if a specific navigation action was called, check if the expected components are rendered after navigation.
+- **Avoid mocking React Navigation**: Mocking React Navigation components can lead to tests that don't match the actual logic. Instead, use a real navigator in your tests.
+
+Following these principles will help you write tests that are more reliable and easier to maintain by avoiding testing implementation details.
+
+## Setting up Jest
+
+### Compiling React Navigation
+
+React Navigation ships [ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). However, Jest does not support ES modules natively.
+
+It's necessary to transform the code to CommonJS to use them in tests. The `react-native` preset for Jest does not transform the code in `node_modules` by default. To enable this, you need to add the [`transformIgnorePatterns`](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) option in your Jest configuration where you can specify a regexp pattern. To compile React Navigation packages, you can add `@react-navigation` to the regexp.
+
+This is usually done in a `jest.config.js` file or the `jest` key in `package.json`:
+
+```diff lang=json
+{
+ "preset": "react-native",
++ "transformIgnorePatterns": [
++ "node_modules/(?!(@react-native|react-native|@react-navigation)/)"
++ ]
+}
+```
+
+### Mocking native dependencies
+
+To be able to test React Navigation components, certain dependencies will need to be mocked depending on which components are being used.
+
+If you're using `@react-navigation/stack`, you will need to mock:
+
+- `react-native-gesture-handler`
+
+If you're using `@react-navigation/drawer`, you will need to mock:
+
+- `react-native-reanimated`
+- `react-native-gesture-handler`
+
+To add the mocks, create a file `jest/setup.js` (or any other file name of your choice) and paste the following code in it:
+
+```js
+// Include this line for mocking react-native-gesture-handler
+import 'react-native-gesture-handler/jestSetup';
+
+// Include this section for mocking react-native-reanimated
+import { setUpTests } from 'react-native-reanimated';
+
+setUpTests();
+
+// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
+import { jest } from '@jest/globals';
+
+jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
+```
+
+Then we need to use this setup file in our jest config. You can add it under [`setupFilesAfterEnv`](https://jestjs.io/docs/configuration#setupfilesafterenv-array) option in a `jest.config.js` file or the `jest` key in `package.json`:
+
+```diff lang=json
+{
+ "preset": "react-native",
+ "transformIgnorePatterns": [
+ "node_modules/(?!(@react-native|react-native|@react-navigation)/)"
+ ],
++ "setupFilesAfterEnv": ["/jest/setup.js"]
+}
+```
+
+Jest will run the files specified in `setupFilesAfterEnv` before running your tests, so it's a good place to put your global mocks.
+
+
+Mocking `react-native-screens`
+
+This shouldn't be necessary in most cases. However, if you find yourself in a need to mock `react-native-screens` component for some reason, you should do it by adding following code in `jest/setup.js` file:
+
+```js
+// Include this section for mocking react-native-screens
+jest.mock('react-native-screens', () => {
+ // Require actual module instead of a mock
+ let screens = jest.requireActual('react-native-screens');
+
+ // All exports in react-native-screens are getters
+ // We cannot use spread for cloning as it will call the getters
+ // So we need to clone it with Object.create
+ screens = Object.create(
+ Object.getPrototypeOf(screens),
+ Object.getOwnPropertyDescriptors(screens)
+ );
+
+ // Add mock of the component you need
+ // Here is the example of mocking the Screen component as a View
+ Object.defineProperty(screens, 'Screen', {
+ value: require('react-native').View,
+ });
+
+ return screens;
+});
+```
+
+
+
+If you're not using Jest, then you'll need to mock these modules according to the test framework you are using.
+
+## Fake timers
+
+When writing tests containing navigation with animations, you need to wait until the animations finish. In such cases, we recommend using [`Fake Timers`](https://jestjs.io/docs/timer-mocks) to simulate the passage of time in your tests. This can be done by adding the following line at the beginning of your test file:
+
+```js
+jest.useFakeTimers();
+```
+
+Fake timers replace real implementation of the native timer functions (e.g. `setTimeout()`, `setInterval()` etc,) with a custom implementation that uses a fake clock. This lets you instantly skip animations and reduce the time needed to run your tests by calling methods such as `jest.runAllTimers()`.
+
+Often, component state is updated after an animation completes. To avoid getting an error in such cases, wrap `jest.runAllTimers()` in `act`:
+
+```js
+import { act } from 'react-test-renderer';
+
+// ...
+
+act(() => jest.runAllTimers());
+```
+
+See the examples below for more details on how to use fake timers in tests involving navigation.
+
+## Navigation and visibility
+
+In React Navigation, the previous screen is not unmounted when navigating to a new screen. This means that the previous screen is still present in the component tree, but it's not visible.
+
+When writing tests, you should assert that the expected component is visible or hidden instead of checking if it's rendered or not. React Native Testing Library provides a `toBeVisible` matcher that can be used to check if an element is visible to the user.
+
+```js
+expect(screen.getByText('Settings screen')).toBeVisible();
+```
+
+This is in contrast to the `toBeOnTheScreen` matcher, which checks if the element is rendered in the component tree. This matcher is not recommended when writing tests involving navigation.
+
+By default, the queries from React Native Testing Library (e.g. `getByRole`, `getByText`, `getByLabelText` etc.) [only return visible elements](https://callstack.github.io/react-native-testing-library/docs/api/queries#includehiddenelements-option). So you don't need to do anything special. However, if you're using a different library for your tests, you'll need to account for this behavior.
+
+## Example tests
+
+We recommend using [React Native Testing Library](https://callstack.github.io/react-native-testing-library/) to write your tests.
+
+In this guide, we will go through some example scenarios and show you how to write tests for them using Jest and React Native Testing Library:
+
+### Navigation between tabs
+
+In this example, we have a bottom tab navigator with two tabs: Home and Settings. We will write a test that asserts that we can navigate between these tabs by pressing the tab bar buttons.
+
+
+
+
+```js title="MyTabs.js"
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { Text, View } from 'react-native';
+
+const HomeScreen = () => {
+ return (
+
+ Home screen
+
+ );
+};
+
+const SettingsScreen = () => {
+ return (
+
+ Settings screen
+
+ );
+};
+
+export const MyTabs = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Settings: SettingsScreen,
+ },
+});
+```
+
+
+
+
+```js title="MyTabs.js"
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { Text, View } from 'react-native';
+
+const HomeScreen = () => {
+ return (
+
+ Home screen
+
+ );
+};
+
+const SettingsScreen = () => {
+ return (
+
+ Settings screen
+
+ );
+};
+
+const Tab = createBottomTabNavigator();
+
+export const MyTabs = () => {
+ return (
+
+
+
+
+ );
+};
+```
+
+
+
+
+
+
+
+```js title="MyTabs.test.js"
+import { expect, jest, test } from '@jest/globals';
+import { createStaticNavigation } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyTabs } from './MyTabs';
+
+jest.useFakeTimers();
+
+test('navigates to settings by tab bar button press', async () => {
+ const user = userEvent.setup();
+
+ const Navigation = createStaticNavigation(MyTabs);
+
+ render( );
+
+ const button = screen.getByRole('button', { name: 'Settings, tab, 2 of 2' });
+
+ await user.press(button);
+
+ act(() => jest.runAllTimers());
+
+ expect(screen.getByText('Settings screen')).toBeVisible();
+});
+```
+
+
+
+
+```js title="MyTabs.test.js"
+import { expect, jest, test } from '@jest/globals';
+import { NavigationContainer } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyTabs } from './MyTabs';
+
+jest.useFakeTimers();
+
+test('navigates to settings by tab bar button press', async () => {
+ const user = userEvent.setup();
+
+ render(
+
+
+
+ );
+
+ const button = screen.getByLabelText('Settings, tab, 2 of 2');
+
+ await user.press(button);
+
+ act(() => jest.runAllTimers());
+
+ expect(screen.getByText('Settings screen')).toBeVisible();
+});
+```
+
+
+
+
+In the above test, we:
+
+- Render the `MyTabs` navigator within a [NavigationContainer](navigation-container.md) in our test.
+- Get the tab bar button using the `getByLabelText` query that matches its accessibility label.
+- Press the button using `userEvent.press(button)` to simulate a user interaction.
+- Run all timers using `jest.runAllTimers()` to skip animations (e.g. animations in the `Pressable` for the button).
+- Assert that the `Settings screen` is visible after the navigation.
+
+### Reacting to a navigation event
+
+In this example, we have a stack navigator with two screens: Home and Surprise. We will write a test that asserts that the text "Surprise!" is displayed after navigating to the Surprise screen.
+
+
+
+
+```js title="MyStack.js"
+import { useNavigation } from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+import { Button, Text, View } from 'react-native';
+import { useEffect, useState } from 'react';
+
+const HomeScreen = () => {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home screen
+ navigation.navigate('Surprise')}
+ title="Click here!"
+ />
+
+ );
+};
+
+const SurpriseScreen = () => {
+ const navigation = useNavigation('Surprise');
+
+ const [textVisible, setTextVisible] = useState(false);
+
+ useEffect(() => {
+ navigation.addListener('transitionEnd', () => setTextVisible(true));
+ }, [navigation]);
+
+ return (
+
+ {textVisible ? Surprise! : ''}
+
+ );
+};
+
+export const MyStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Surprise: SurpriseScreen,
+ },
+});
+```
+
+
+
+
+```js title="MyStack.js"
+import { useNavigation } from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+import { useEffect, useState } from 'react';
+import { Button, Text, View } from 'react-native';
+
+const HomeScreen = () => {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home screen
+ navigation.navigate('Surprise')}
+ title="Click here!"
+ />
+
+ );
+};
+
+const SurpriseScreen = () => {
+ const navigation = useNavigation('Surprise');
+
+ const [textVisible, setTextVisible] = useState(false);
+
+ useEffect(() => {
+ navigation.addListener('transitionEnd', () => setTextVisible(true));
+ }, [navigation]);
+
+ return (
+
+ {textVisible ? Surprise! : ''}
+
+ );
+};
+
+const Stack = createStackNavigator();
+
+export const MyStack = () => {
+ return (
+
+
+
+
+ );
+};
+```
+
+
+
+
+
+
+
+```js title="MyStack.test.js"
+import { expect, jest, test } from '@jest/globals';
+import { createStaticNavigation } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyStack } from './MyStack';
+
+jest.useFakeTimers();
+
+test('shows surprise text after navigating to surprise screen', async () => {
+ const user = userEvent.setup();
+
+ const Navigation = createStaticNavigation(MyStack);
+
+ render( );
+
+ await user.press(screen.getByLabelText('Click here!'));
+
+ act(() => jest.runAllTimers());
+
+ expect(screen.getByText('Surprise!')).toBeVisible();
+});
+```
+
+
+
+
+```js title="MyStack.test.js"
+import { expect, jest, test } from '@jest/globals';
+import { NavigationContainer } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyStack } from './MyStack';
+
+jest.useFakeTimers();
+
+test('shows surprise text after navigating to surprise screen', async () => {
+ const user = userEvent.setup();
+
+ render(
+
+
+
+ );
+
+ await user.press(screen.getByLabelText('Click here!'));
+
+ act(() => jest.runAllTimers());
+
+ expect(screen.getByText('Surprise!')).toBeVisible();
+});
+```
+
+
+
+
+In the above test, we:
+
+- Render the `MyStack` navigator within a [NavigationContainer](navigation-container.md) in our test.
+- Get the button using the `getByLabelText` query that matches its title.
+- Press the button using `userEvent.press(button)` to simulate a user interaction.
+- Run all timers using `jest.runAllTimers()` to skip animations (e.g. navigation animation between screens).
+- Assert that the `Surprise!` text is visible after the transition to the Surprise screen is complete.
+
+### Fetching data with `useFocusEffect`
+
+In this example, we have a bottom tab navigator with two tabs: Home and Pokemon. We will write a test that asserts the data fetching logic on focus in the Pokemon screen.
+
+
+
+
+```js title="MyTabs.js"
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { useFocusEffect } from '@react-navigation/native';
+import { useCallback, useState } from 'react';
+import { Text, View } from 'react-native';
+
+function HomeScreen() {
+ return (
+
+ Home screen
+
+ );
+}
+
+const url = 'https://pokeapi.co/api/v2/pokemon/ditto';
+
+function PokemonScreen() {
+ const [profileData, setProfileData] = useState({ status: 'loading' });
+
+ useFocusEffect(
+ useCallback(() => {
+ if (profileData.status === 'success') {
+ return;
+ }
+
+ setProfileData({ status: 'loading' });
+
+ const controller = new AbortController();
+
+ const fetchUser = async () => {
+ try {
+ const response = await fetch(url, { signal: controller.signal });
+ const data = await response.json();
+
+ setProfileData({ status: 'success', data: data });
+ } catch (error) {
+ setProfileData({ status: 'error' });
+ }
+ };
+
+ fetchUser();
+
+ return () => {
+ controller.abort();
+ };
+ }, [profileData.status])
+ );
+
+ if (profileData.status === 'loading') {
+ return (
+
+ Loading...
+
+ );
+ }
+
+ if (profileData.status === 'error') {
+ return (
+
+ An error occurred!
+
+ );
+ }
+
+ return (
+
+ {profileData.data.name}
+
+ );
+}
+
+export const MyTabs = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Pokemon: PokemonScreen,
+ },
+});
+```
+
+
+
+
+```js title="MyTabs.js"
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { useFocusEffect } from '@react-navigation/native';
+import { useCallback, useState } from 'react';
+import { Text, View } from 'react-native';
+
+function HomeScreen() {
+ return (
+
+ Home screen
+
+ );
+}
+
+const url = 'https://pokeapi.co/api/v2/pokemon/ditto';
+
+function PokemonInfoScreen() {
+ const [profileData, setProfileData] = useState({ status: 'loading' });
+
+ useFocusEffect(
+ useCallback(() => {
+ if (profileData.status === 'success') {
+ return;
+ }
+
+ setProfileData({ status: 'loading' });
+
+ const controller = new AbortController();
+
+ const fetchUser = async () => {
+ try {
+ const response = await fetch(url, { signal: controller.signal });
+ const data = await response.json();
+
+ setProfileData({ status: 'success', data: data });
+ } catch (error) {
+ setProfileData({ status: 'error' });
+ }
+ };
+
+ fetchUser();
+
+ return () => {
+ controller.abort();
+ };
+ }, [profileData.status])
+ );
+
+ if (profileData.status === 'loading') {
+ return (
+
+ Loading...
+
+ );
+ }
+
+ if (profileData.status === 'error') {
+ return (
+
+ An error occurred!
+
+ );
+ }
+
+ return (
+
+ {profileData.data.name}
+
+ );
+}
+
+const Tab = createBottomTabNavigator();
+
+export function MyTabs() {
+ return (
+
+
+
+
+ );
+}
+```
+
+
+
+
+To make the test deterministic and isolate it from the real backend, you can mock the network requests with a library such as [Mock Service Worker](https://mswjs.io/):
+
+```js title="msw-handlers.js"
+import { delay, http, HttpResponse } from 'msw';
+
+export const handlers = [
+ http.get('https://pokeapi.co/api/v2/pokemon/ditto', async () => {
+ await delay(1000);
+
+ return HttpResponse.json({
+ id: 132,
+ name: 'ditto',
+ });
+ }),
+];
+```
+
+Here we setup a handler that mocks responses from the API (for this example we're using [PokéAPI](https://pokeapi.co/)). Additionally, we `delay` the response by 1000ms to simulate a network request delay.
+
+Then, we write a Node.js integration module to use the Mock Service Worker in our tests:
+
+```js title="msw-node.js"
+import { setupServer } from 'msw/node';
+import { handlers } from './msw-handlers';
+
+const server = setupServer(...handlers);
+```
+
+Refer to the documentation of the library to learn more about setting it up in your project - [Getting started](https://mswjs.io/docs/getting-started), [React Native integration](https://mswjs.io/docs/integrations/react-native).
+
+
+
+
+```js title="MyTabs.test.js"
+import './msw-node';
+
+import { expect, jest, test } from '@jest/globals';
+import { createStaticNavigation } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyTabs } from './MyTabs';
+
+jest.useFakeTimers();
+
+test('loads data on Pokemon info screen after focus', async () => {
+ const user = userEvent.setup();
+
+ const Navigation = createStaticNavigation(MyTabs);
+
+ render( );
+
+ const homeTabButton = screen.getByLabelText('Home, tab, 1 of 2');
+ const profileTabButton = screen.getByLabelText('Profile, tab, 2 of 2');
+
+ await user.press(profileTabButton);
+
+ expect(screen.getByText('Loading...')).toBeVisible();
+
+ await act(() => jest.runAllTimers());
+
+ expect(screen.getByText('ditto')).toBeVisible();
+
+ await user.press(homeTabButton);
+
+ await act(() => jest.runAllTimers());
+
+ await user.press(profileTabButton);
+
+ expect(screen.queryByText('Loading...')).not.toBeVisible();
+ expect(screen.getByText('ditto')).toBeVisible();
+});
+```
+
+
+
+
+```js title="MyTabs.test.js"
+import './msw-node';
+
+import { expect, jest, test } from '@jest/globals';
+import { NavigationContainer } from '@react-navigation/native';
+import { act, render, screen, userEvent } from '@testing-library/react-native';
+
+import { MyTabs } from './MyTabs';
+
+jest.useFakeTimers();
+
+test('loads data on Pokemon info screen after focus', async () => {
+ const user = userEvent.setup();
+
+ render(
+
+
+
+ );
+
+ const homeTabButton = screen.getByLabelText('Home, tab, 1 of 2');
+ const profileTabButton = screen.getByLabelText('Profile, tab, 2 of 2');
+
+ await user.press(profileTabButton);
+
+ expect(screen.getByText('Loading...')).toBeVisible();
+
+ await act(() => jest.runAllTimers());
+
+ expect(screen.getByText('ditto')).toBeVisible();
+
+ await user.press(homeTabButton);
+
+ await act(() => jest.runAllTimers());
+
+ await user.press(profileTabButton);
+
+ expect(screen.queryByText('Loading...')).not.toBeVisible();
+ expect(screen.getByText('ditto')).toBeVisible();
+});
+```
+
+
+
+
+In the above test, we:
+
+- Assert that the `Loading...` text is visible while the data is being fetched.
+- Run all timers using `jest.runAllTimers()` to skip delays in the network request.
+- Assert that the `ditto` text is visible after the data is fetched.
+- Press the home tab button to navigate to the home screen.
+- Run all timers using `jest.runAllTimers()` to skip animations (e.g. animations in the `Pressable` for the button).
+- Press the profile tab button to navigate back to the Pokemon screen.
+- Ensure that cached data is shown by asserting that the `Loading...` text is not visible and the `ditto` text is visible.
+
+:::note
+
+In a production app, we recommend using a library like [React Query](https://tanstack.com/query/) to handle data fetching and caching. The above example is for demonstration purposes only.
+
+:::
+
+### Re-usable components
+
+To make it easier to test components that don't depend on the navigation structure, we can create a light-weight test navigator:
+
+```js title="TestStackNavigator.js"
+import { useNavigationBuilder, StackRouter } from '@react-navigation/native';
+
+function TestStackNavigator(props) {
+ const { state, descriptors, NavigationContent } = useNavigationBuilder(
+ StackRouter,
+ props
+ );
+
+ return (
+
+ {state.routes.map((route, index) => {
+ return (
+
+ {descriptors[route.key].render()}
+
+ );
+ })}
+
+ );
+}
+
+export function createTestStackNavigator(config) {
+ return createNavigatorFactory(TestStackNavigator)(config);
+}
+```
+
+This lets us test React Navigation specific logic such as `useFocusEffect` without needing to set up a full navigator.
+
+We can use this test navigator in our tests like this:
+
+
+
+
+```js title="MyComponent.test.js"
+import { act, render, screen } from '@testing-library/react-native';
+import { createStaticNavigation } from '@react-navigation/native';
+import { createTestStackNavigator } from './TestStackNavigator';
+import { MyComponent } from './MyComponent';
+
+test('does not show modal when not focused', () => {
+ const TestStack = createTestStackNavigator({
+ screens: {
+ A: MyComponent,
+ B: () => null,
+ },
+ });
+
+ const Navigation = createStaticNavigation(TestStack);
+
+ render(
+
+ );
+
+ expect(screen.queryByText('Modal')).not.toBeVisible();
+});
+
+test('shows modal when focused', () => {
+ const TestStack = createTestStackNavigator({
+ screens: {
+ A: MyComponent,
+ B: () => null,
+ },
+ });
+
+ const Navigation = createStaticNavigation(TestStack);
+
+ render(
+
+ );
+
+ expect(screen.getByText('Modal')).toBeVisible();
+});
+```
+
+
+
+
+```js title="MyComponent.test.js"
+import { act, render, screen } from '@testing-library/react-native';
+import { NavigationContainer } from '@react-navigation/native';
+import { createTestStackNavigator } from './TestStackNavigator';
+import { MyComponent } from './MyComponent';
+
+test('does not show modal when not focused', () => {
+ const Stack = createTestStackNavigator();
+
+ const TestStack = () => (
+
+
+ null} />
+
+ );
+
+ render(
+
+
+
+ );
+
+ expect(screen.queryByText('Modal')).not.toBeVisible();
+});
+
+test('shows modal when focused', () => {
+ const Stack = createTestStackNavigator();
+
+ const TestStack = () => (
+
+
+ null} />
+
+ );
+
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('Modal')).toBeVisible();
+});
+```
+
+
+
+
+Here we create a test stack navigator using the `createTestStackNavigator` function. We then render the `MyComponent` component within the test navigator and assert that the modal is shown or hidden based on the focus state.
+
+The `initialState` prop is used to set the initial state of the navigator, i.e. which screens are rendered in the stack and which one is focused. See [navigation state](navigation-state.md) for more information on the structure of the state object.
+
+You can also pass a [`ref`](navigation-container.md#ref) to programmatically navigate in your tests.
+
+The test navigator is a simplified version of the stack navigator, but it's still a real navigator and behaves like one. This means that you can use it to test any other navigation logic.
+
+See [Custom navigators](custom-navigators.md) for more information on how to write custom navigators if you want adjust the behavior of the test navigator or add more functionality.
+
+## Best practices
+
+Generally, we recommend avoiding mocking React Navigation. Mocking can help you isolate the component you're testing, but when testing components with navigation logic, mocking means that your tests don't test for the navigation logic.
+
+- Mocking APIs such as `useFocusEffect` means you're not testing the focus logic in your component.
+- Mocking `navigation` prop or `useNavigation` means that the `navigation` object may not have the same shape as the real one.
+- Asserting `navigation.navigate` calls means you only test that the function was called, not that the call was correct based on the navigation structure.
+- etc.
+
+Avoiding mocks means additional work when writing tests, but it also means:
+
+- Refactors that don't change the logic won't break the tests, e.g. changing `navigation` prop to `useNavigation`, using a different navigation action that does the same thing, etc.
+- Library upgrades or refactor that actually change the behavior will correctly break the tests, surfacing actual regressions.
+
+Tests should break when there's a regression, not due to a refactor. Otherwise it leads to additional work to fix the tests, making it harder to know when a regression is introduced.
diff --git a/versioned_docs/version-8.x/themes.md b/versioned_docs/version-8.x/themes.md
new file mode 100755
index 00000000000..e9ced1c571a
--- /dev/null
+++ b/versioned_docs/version-8.x/themes.md
@@ -0,0 +1,853 @@
+---
+id: themes
+title: Themes
+sidebar_label: Themes
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+Themes allow you to change the colors and fonts of various components provided by React Navigation. You can use themes to:
+
+- Customize the colors and fonts to match your brand
+- Provide light and dark themes based on the time of the day or user preference
+
+## Basic usage
+
+To pass a custom theme, you can pass the `theme` prop to the navigation container.
+
+
+
+
+```js name="Simple theme" snack
+// codeblock-focus-start
+import * as React from 'react';
+import {
+ useNavigation,
+ createStaticNavigation,
+ DefaultTheme,
+} from '@react-navigation/native';
+// codeblock-focus-end
+import { View, Text } from 'react-native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+
+// codeblock-focus-start
+
+const MyTheme = {
+ ...DefaultTheme,
+ colors: {
+ ...DefaultTheme.colors,
+ background: 'rgb(140, 201, 125)',
+ primary: 'rgb(255, 45, 85)',
+ },
+};
+// codeblock-focus-end
+
+function SettingsScreen({ route }) {
+ const navigation = useNavigation('Settings');
+ const { user } = route.params;
+
+ return (
+
+ Settings Screen
+ userParam: {JSON.stringify(user)}
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ return (
+
+ Profile Screen
+
+ );
+}
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home Screen
+
+ navigation.navigate('Panel', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const PanelStack = createNativeStackNavigator({
+ screens: {
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Drawer = createDrawerNavigator({
+ initialRouteName: 'Panel',
+ screens: {
+ Home: HomeScreen,
+ Panel: PanelStack,
+ },
+});
+
+// codeblock-focus-start
+
+const Navigation = createStaticNavigation(Drawer);
+
+export default function App() {
+ // highlight-next-line
+ return ;
+}
+// codeblock-focus-end
+```
+
+
+
+
+```js name="Simple theme" snack
+// codeblock-focus-start
+import * as React from 'react';
+import {
+ NavigationContainer,
+ DefaultTheme,
+ useNavigation,
+} from '@react-navigation/native';
+// codeblock-focus-end
+import { View, Text } from 'react-native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+
+// codeblock-focus-start
+
+const MyTheme = {
+ ...DefaultTheme,
+ colors: {
+ ...DefaultTheme.colors,
+ background: 'rgb(140, 201, 125)',
+ primary: 'rgb(255, 45, 85)',
+ },
+};
+// codeblock-focus-end
+
+function SettingsScreen({ route }) {
+ const navigation = useNavigation('Settings');
+ const { user } = route.params;
+
+ return (
+
+ Settings Screen
+ userParam: {JSON.stringify(user)}
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ Home Screen
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const Drawer = createDrawerNavigator();
+const Stack = createNativeStackNavigator();
+
+function Root() {
+ return (
+
+
+
+
+ );
+}
+
+// codeblock-focus-start
+
+export default function App() {
+ return (
+ // highlight-next-line
+
+
+
+
+
+
+ );
+}
+// codeblock-focus-start
+```
+
+
+
+
+You can change the theme prop dynamically and all the components will automatically update to reflect the new theme. If you haven't provided a `theme` prop, the default theme will be used.
+
+## Properties
+
+A theme is a JS object containing a list of colors to use. It contains the following properties:
+
+- `dark` (`boolean`): Whether this is a dark theme or a light theme
+- `colors` (`object`): Various colors used by react navigation components:
+ - `primary` (`string`): The primary color of the app used to tint various elements. Usually you'll want to use your brand color for this.
+ - `background` (`string`): The color of various backgrounds, such as the background color for the screens.
+ - `card` (`string`): The background color of card-like elements, such as headers, tab bars etc.
+ - `text` (`string`): The text color of various elements.
+ - `border` (`string`): The color of borders, e.g. header border, tab bar border etc.
+ - `notification` (`string`): The color of notifications and badge (e.g. badge in bottom tabs).
+- `fonts` (`object`): Various fonts used by react navigation components:
+ - `regular` (`object`): Style object for the primary font used in the app.
+ - `medium` (`object`): Style object for the semi-bold variant of the primary font.
+ - `bold` (`object`): Style object for the bold variant of the primary font.
+ - `heavy` (`object`): Style object for the extra-bold variant of the primary font.
+
+The style objects for fonts contain the following properties:
+
+- `fontFamily` (`string`): The name of the font family (or font stack on Web) to use, e.g. `Roboto` or `Helvetica Neue`. The system fonts are used by default.
+- `fontWeight` (`string`): The font weight to use. Valid values are `normal`, `bold`, `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900`.
+
+When creating a custom theme, you will need to provide all of these properties.
+
+Example theme:
+
+```js
+const WEB_FONT_STACK =
+ 'system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
+
+const MyTheme = {
+ dark: false,
+ colors: {
+ primary: 'rgb(255, 45, 85)',
+ background: 'rgb(242, 242, 242)',
+ card: 'rgb(255, 255, 255)',
+ text: 'rgb(28, 28, 30)',
+ border: 'rgb(199, 199, 204)',
+ notification: 'rgb(255, 69, 58)',
+ },
+ fonts: Platform.select({
+ web: {
+ regular: {
+ fontFamily: WEB_FONT_STACK,
+ fontWeight: '400',
+ },
+ medium: {
+ fontFamily: WEB_FONT_STACK,
+ fontWeight: '500',
+ },
+ bold: {
+ fontFamily: WEB_FONT_STACK,
+ fontWeight: '600',
+ },
+ heavy: {
+ fontFamily: WEB_FONT_STACK,
+ fontWeight: '700',
+ },
+ },
+ ios: {
+ regular: {
+ fontFamily: 'System',
+ fontWeight: '400',
+ },
+ medium: {
+ fontFamily: 'System',
+ fontWeight: '500',
+ },
+ bold: {
+ fontFamily: 'System',
+ fontWeight: '600',
+ },
+ heavy: {
+ fontFamily: 'System',
+ fontWeight: '700',
+ },
+ },
+ default: {
+ regular: {
+ fontFamily: 'sans-serif',
+ fontWeight: 'normal',
+ },
+ medium: {
+ fontFamily: 'sans-serif-medium',
+ fontWeight: 'normal',
+ },
+ bold: {
+ fontFamily: 'sans-serif',
+ fontWeight: '600',
+ },
+ heavy: {
+ fontFamily: 'sans-serif',
+ fontWeight: '700',
+ },
+ },
+ }),
+};
+```
+
+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.
+
+You can import the default and dark themes like so:
+
+```js
+import { DefaultTheme, DarkTheme } from '@react-navigation/native';
+```
+
+## Keeping the native theme in sync
+
+If you're changing the theme in the app, native UI elements such as Alert, ActionSheet etc. won't reflect the new theme. You can do the following to keep the native theme in sync:
+
+```js
+React.useEffect(() => {
+ const colorScheme = theme.dark ? 'dark' : 'light';
+
+ if (Platform.OS === 'web') {
+ document.documentElement.style.colorScheme = colorScheme;
+ } else {
+ Appearance.setColorScheme(colorScheme);
+ }
+}, [theme.dark]);
+```
+
+Alternatively, you can use the [`useColorScheme`](#using-the-operating-system-preferences) hook to get the current native color scheme and update the theme accordingly.
+
+## Using the operating system preferences
+
+On iOS 13+ and Android 10+, you can get user's preferred color scheme (`'dark'` or `'light'`) with the ([`useColorScheme` hook](https://reactnative.dev/docs/usecolorscheme)).
+
+
+
+
+```js name="Operating system color theme" snack
+import * as React from 'react';
+// codeblock-focus-start
+import {
+ useNavigation,
+ createStaticNavigation,
+ DefaultTheme,
+ DarkTheme,
+ useTheme,
+} from '@react-navigation/native';
+import { View, Text, TouchableOpacity, useColorScheme } from 'react-native';
+// codeblock-focus-end
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+
+function SettingsScreen({ route }) {
+ const navigation = useNavigation('Settings');
+ const { user } = route.params;
+ const { colors } = useTheme();
+
+ return (
+
+ Settings Screen
+
+ userParam: {JSON.stringify(user)}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+function MyButton() {
+ const { colors } = useTheme();
+
+ return (
+
+ Button!
+
+ );
+}
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const { colors } = useTheme();
+
+ return (
+
+ Home Screen
+
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const PanelStack = createNativeStackNavigator({
+ screens: {
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Drawer = createDrawerNavigator({
+ initialRouteName: 'Panel',
+ screens: {
+ Home: HomeScreen,
+ Panel: PanelStack,
+ },
+});
+
+// codeblock-focus-start
+
+const Navigation = createStaticNavigation(Drawer);
+
+export default function App() {
+ // highlight-next-line
+ const scheme = useColorScheme();
+
+ // highlight-next-line
+ return ;
+}
+
+// codeblock-focus-end
+```
+
+
+
+
+```js name="Operating system color theme" snack
+import * as React from 'react';
+// codeblock-focus-start
+import { View, Text, TouchableOpacity, useColorScheme } from 'react-native';
+import {
+ NavigationContainer,
+ DefaultTheme,
+ DarkTheme,
+ useTheme,
+} from '@react-navigation/native';
+// codeblock-focus-end
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+
+function SettingsScreen({ route, navigation }) {
+ const { user } = route.params;
+ const { colors } = useTheme();
+
+ return (
+
+ Settings Screen
+
+ userParam: {JSON.stringify(user)}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+function MyButton() {
+ const { colors } = useTheme();
+
+ return (
+
+ Button!
+
+ );
+}
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const { colors } = useTheme();
+
+ return (
+
+ Home Screen
+
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const Drawer = createDrawerNavigator();
+const Stack = createNativeStackNavigator();
+
+function Root() {
+ return (
+
+
+
+
+ );
+}
+
+// codeblock-focus-start
+
+export default function App() {
+ // highlight-next-line
+ const scheme = useColorScheme();
+
+ return (
+ // highlight-next-line
+
+
+
+
+
+
+ );
+}
+// codeblock-focus-end
+```
+
+
+
+
+## Using the current theme in your own components
+
+To gain access to the theme in any component that is rendered inside the navigation container:, you can use the `useTheme` hook. It returns the theme object:
+
+
+
+
+```js name="System themes" snack
+import * as React from 'react';
+// codeblock-focus-start
+import {
+ useNavigation,
+ createStaticNavigation,
+ DefaultTheme,
+ DarkTheme,
+ useTheme,
+} from '@react-navigation/native';
+import { View, Text, TouchableOpacity, useColorScheme } from 'react-native';
+// codeblock-focus-end
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+
+function SettingsScreen({ route }) {
+ const navigation = useNavigation('Settings');
+ const { user } = route.params;
+ const { colors } = useTheme();
+
+ return (
+
+ Settings Screen
+
+ userParam: {JSON.stringify(user)}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+// codeblock-focus-start
+
+function MyButton() {
+ // highlight-next-line
+ const { colors } = useTheme();
+
+ return (
+
+ Button!
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const { colors } = useTheme();
+
+ return (
+
+ Home Screen
+
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const PanelStack = createNativeStackNavigator({
+ screens: {
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Drawer = createDrawerNavigator({
+ initialRouteName: 'Panel',
+ screens: {
+ Home: HomeScreen,
+ Panel: PanelStack,
+ },
+});
+
+const Navigation = createStaticNavigation(Drawer);
+
+export default function App() {
+ const scheme = useColorScheme();
+
+ return ;
+}
+```
+
+
+
+
+```js name="System themes" snack
+import * as React from 'react';
+// codeblock-focus-start
+import { View, Text, TouchableOpacity, useColorScheme } from 'react-native';
+import {
+ NavigationContainer,
+ DefaultTheme,
+ DarkTheme,
+ useTheme,
+ useNavigation,
+} from '@react-navigation/native';
+// codeblock-focus-end
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+
+function SettingsScreen({ route, navigation }) {
+ const { colors } = useTheme();
+ const { user } = route.params;
+
+ return (
+
+ Settings Screen
+
+ userParam: {JSON.stringify(user)}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+// codeblock-focus-start
+
+function MyButton() {
+ // highlight-next-line
+ const { colors } = useTheme();
+
+ return (
+
+ Button!
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const { colors } = useTheme();
+
+ return (
+
+ Home Screen
+
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const Drawer = createDrawerNavigator();
+const Stack = createNativeStackNavigator();
+
+function Root() {
+ return (
+
+
+
+
+ );
+}
+
+export default function App() {
+ const scheme = useColorScheme();
+
+ return (
+
+
+
+
+
+
+ );
+}
+```
+
+
+
diff --git a/versioned_docs/version-8.x/troubleshooting.md b/versioned_docs/version-8.x/troubleshooting.md
new file mode 100755
index 00000000000..1186ea690eb
--- /dev/null
+++ b/versioned_docs/version-8.x/troubleshooting.md
@@ -0,0 +1,491 @@
+---
+id: troubleshooting
+title: Troubleshooting
+sidebar_label: Troubleshooting
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+This section attempts to outline issues that users frequently encounter when first getting accustomed to using React Navigation. These issues may or may not be related to React Navigation itself.
+
+Before troubleshooting an issue, make sure that you have upgraded to **the latest available versions** of the packages. You can install the latest versions by installing the packages again (e.g. `npm install package-name`).
+
+## I'm getting an error "Unable to resolve module" after updating to the latest version
+
+This might happen for 3 reasons:
+
+### Stale cache of Metro bundler
+
+If the module points to a local file (i.e. the name of the module starts with `./`), then it's probably due to stale cache. To fix this, try the following solutions.
+
+If you're using Expo, run:
+
+```bash
+expo start -c
+```
+
+If you're not using Expo, run:
+
+```bash
+npx react-native start --reset-cache
+```
+
+If that doesn't work, you can also try the following:
+
+```bash
+rm -rf $TMPDIR/metro-bundler-cache-*
+```
+
+### Missing peer dependency
+
+If the module points to an npm package (i.e. the name of the module doesn't with `./`), then it's probably due to a missing dependency. To fix this, install the dependency in your project:
+
+```bash npm2yarn
+npm install name-of-the-module
+```
+
+Sometimes it might even be due to a corrupt installation. If clearing cache didn't work, try deleting your `node_modules` folder and run `npm install` again.
+
+### Missing extensions in metro configuration
+
+Sometimes the error may look like this:
+
+```bash
+Error: While trying to resolve module "@react-navigation/native" from file "/path/to/src/App.js", the package "/path/to/node_modules/@react-navigation/native/package.json" was successfully found. However, this package itself specifies a "main" module field that could not be resolved ("/path/to/node_modules/@react-navigation/native/src/index.tsx"
+```
+
+This can happen if you have a custom configuration for metro and haven't specified `ts` and `tsx` as valid extensions. These extensions are present in the default configuration. To check if this is the issue, look for a `metro.config.js` file in your project and check if you have specified the [`sourceExts`](https://facebook.github.io/metro/docs/en/configuration#sourceexts) option. It should at least have the following configuration:
+
+```js
+sourceExts: ['js', 'json', 'ts', 'tsx'];
+```
+
+If it's missing these extensions, add them and then clear metro cache as shown in the section above.
+
+## I'm getting "SyntaxError in @react-navigation/xxx/xxx.tsx" or "SyntaxError: /xxx/@react-navigation/xxx/xxx.tsx: Unexpected token"
+
+This might happen if you have an old version of the `@react-native/babel-preset` package. Try upgrading it to the latest version.
+
+```bash npm2yarn
+npm install --save-dev @react-native/babel-preset
+```
+
+If you have `@babel/core` installed, also upgrade it to latest version.
+
+```bash npm2yarn
+npm install --save-dev @babel/core
+```
+
+If upgrading the packages don't help, you can also try deleting your `node_modules` and then the lock the file and reinstall your dependencies.
+
+If you use `npm`:
+
+```bash
+rm -rf node_modules
+rm package-lock.json
+npm install
+```
+
+If you use `yarn`:
+
+```bash
+rm -rf node_modules
+rm yarn.lock
+yarn
+```
+
+:::warning
+
+Deleting the lockfile is generally not recommended as it may upgrade your dependencies to versions that haven't been tested with your project. So only use this as a last resort.
+
+:::
+
+After upgrading or reinstalling the packages, you should also clear Metro bundler's cache following the instructions earlier in the page.
+
+## I'm getting "Module '[...]' has no exported member 'xxx' when using TypeScript
+
+This might happen if you have an old version of TypeScript in your project. You can try upgrading it:
+
+```bash npm2yarn
+npm install --save-dev typescript
+```
+
+## I'm getting an error "null is not an object (evaluating 'RNGestureHandlerModule.default.Direction')"
+
+This and some similar errors might occur if you have a bare React Native project and the library [`react-native-gesture-handler`](https://github.com/software-mansion/react-native-gesture-handler) library isn't linked.
+
+Linking is automatic from React Native 0.60, so if you have linked the library manually, first unlink it:
+
+```bash
+react-native unlink react-native-gesture-handler
+```
+
+If you're testing on iOS and use Mac, make sure you have run `pod install` in the `ios/` folder:
+
+```bash
+cd ios
+pod install
+cd ..
+```
+
+Now rebuild the app and test on your device or simulator.
+
+## I'm getting an error "requireNativeComponent: "RNCSafeAreaProvider" was not found in the UIManager"
+
+This and some similar errors might occur if you have a bare React Native project and the library [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context) library isn't linked.
+
+Linking is automatic from React Native 0.60, so if you have linked the library manually, first unlink it:
+
+```bash
+react-native unlink react-native-safe-area-context
+```
+
+If you're testing on iOS and use Mac, make sure you have run `pod install` in the `ios/` folder:
+
+```bash
+cd ios
+pod install
+cd ..
+```
+
+Now rebuild the app and test on your device or simulator.
+
+## I'm getting an error "Tried to register two views with the same name RNCSafeAreaProvider"
+
+This might occur if you have multiple versions of [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context) installed.
+
+If you're using Expo managed workflow, it's likely that you have installed an incompatible version. To install the correct version, run:
+
+```bash
+npx expo install react-native-safe-area-context
+```
+
+If it didn't fix the error or you're not using Expo managed workflow, you'll need to check which package depends on a different version of `react-native-safe-area-context`.
+
+If you use `yarn`, run:
+
+```bash
+yarn why react-native-safe-area-context
+```
+
+If you use `npm`, run:
+
+```bash
+npm ls react-native-safe-area-context
+```
+
+This will tell you if a package you use has a dependency on `react-native-safe-area-context`. If it's a third-party package, you should open an issue on the relevant repo's issue tracker explaining the problem. Generally for libraries, dependencies containing native code should be defined in `peerDependencies` instead of `dependencies` to avoid such issues.
+
+If it's already in `peerDependencies` and not in `dependencies`, and you use `npm`, it might be because of incompatible version range defined for the package. The author of the library will need to relax the version range in such cases to allow a wider range of versions to be installed.
+
+If you use `yarn`, you can also temporarily override the version being installed using `resolutions`. Add the following in your `package.json`:
+
+```json
+"resolutions": {
+ "react-native-safe-area-context": ""
+}
+```
+
+And then run:
+
+```bash
+yarn
+```
+
+If you're on iOS and not using Expo managed workflow, also run:
+
+```bash
+cd ios
+pod install
+cd ..
+```
+
+Now rebuild the app and test on your device or simulator.
+
+## Nothing is visible on the screen after adding a `View`
+
+If you wrap the container in a `View`, make sure the `View` stretches to fill the container using `flex: 1`:
+
+
+
+
+```js
+import * as React from 'react';
+import { View } from 'react-native';
+import { createStaticNavigation } from '@react-navigation/native';
+
+/* ... */
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return (
+ // highlight-next-line
+
+
+
+ );
+}
+```
+
+
+
+
+```js
+import * as React from 'react';
+import { View } from 'react-native';
+import { NavigationContainer } from '@react-navigation/native';
+
+export default function App() {
+ return (
+ // highlight-next-line
+
+ {/* ... */}
+
+ );
+}
+```
+
+
+
+
+## I get the warning "Non-serializable values were found in the navigation state"
+
+This can happen if you are passing non-serializable values such as class instances, functions etc. in params. React Navigation warns you in this case because this can break other functionality such [state persistence](state-persistence.md), [deep linking](deep-linking.md), [web support](web-support.md) etc.
+
+Example of some use cases for passing functions in params are the following:
+
+- To pass a callback to use in a header button. This can be achieved using `navigation.setOptions` instead. See the [guide for header buttons](header-buttons.md#header-interaction-with-its-screen-component) for examples.
+- To pass a callback to the next screen which it can call to pass some data back. You can usually achieve it using `popTo` instead. See [passing params to a previous screen](params.md#passing-params-to-a-previous-screen) for examples.
+- To pass complex data to another screen. Instead of passing the data `params`, you can store that complex data somewhere else (like a global store), and pass an id instead. Then the screen can get the data from the global store using the id. See [what should be in params](params.md#what-should-be-in-params).
+- Pass data, callbacks etc. from a parent to child screens. You can either use React Context, or pass a children callback to pass these down instead of using params. See [passing additional props](hello-react-navigation.md#passing-additional-props).
+
+We don't generally recommend passing functions in params. But if you don't use state persistence, deep links, or use React Navigation on Web, then you can choose to ignore it. To ignore the warning, you can use `LogBox.ignoreLogs`.
+
+Example:
+
+```js
+import { LogBox } from 'react-native';
+
+LogBox.ignoreLogs([
+ 'Non-serializable values were found in the navigation state',
+]);
+```
+
+## I'm getting "Invalid hook call. Hooks can only be called inside of the body of a function component"
+
+This can happen when you pass a React component to an option that accepts a function returning a react element. For example, the [`headerTitle` option in native stack navigator](native-stack-navigator.md#headertitle) expects a function returning a react element:
+
+
+
+
+```js
+const Stack = createNativeStackNavigator({
+ screens: {
+ Home: {
+ screen: Home,
+ options: {
+ // highlight-next-line
+ headerTitle: (props) => ,
+ },
+ },
+ },
+});
+```
+
+
+
+
+```js
+ ,
+ }}
+/>
+```
+
+
+
+
+If you directly pass a function here, you'll get this error when using hooks:
+
+
+
+
+```js
+const Stack = createNativeStackNavigator({
+ screens: {
+ Home: {
+ screen: Home,
+ options: {
+ // This is not correct
+ // highlight-next-line
+ headerTitle: MyTitle,
+ },
+ },
+ },
+});
+```
+
+
+
+
+```js
+
+```
+
+
+
+
+The same applies to other options like `headerLeft`, `headerRight`, `tabBarIcon` etc. as well as props such as `tabBar`, `drawerContent` etc.
+
+## Screens are unmounting/remounting during navigation
+
+Sometimes you might have noticed that your screens unmount/remount, or your local component state or the navigation state resets when you navigate. This might happen if you are creating React components during render.
+
+The simplest example is something like following:
+
+```js
+function App() {
+ return (
+
+ {
+ return ;
+ }}
+ />
+
+ );
+}
+```
+
+The `component` prop expects a React Component, but in the example, it's getting a function returning an React Element. While superficially a component and a function returning a React Element look the exact same, they don't behave the same way when used.
+
+Here, every time the component re-renders, a new function will be created and passed to the `component` prop. React will see a new component and unmount the previous component before rendering the new one. This will cause any local state in the old component to be lost. React Navigation will detect and warn for this specific case but there can be other ways you might be creating components during render which it can't detect.
+
+Another easy to identify example of this is when you create a component inside another component:
+
+
+
+
+```js
+function App() {
+ const Home = () => {
+ return ;
+ };
+
+ const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: Home,
+ },
+ });
+
+ const Navigation = createStaticNavigation(RootStack);
+
+ return ;
+}
+```
+
+
+
+
+```js
+function App() {
+ const Home = () => {
+ return ;
+ };
+
+ return (
+
+
+
+ );
+}
+```
+
+
+
+
+Or when you use a higher order component (such as `connect` from Redux, or `withX` functions that accept a component) inside another component:
+
+```js
+function App() {
+ return (
+
+
+
+ );
+}
+```
+
+If you're unsure, it's always best to make sure that the components you are using as screens are defined outside of a React component. They could be defined in another file and imported, or defined at the top level scope in the same file:
+
+
+
+
+```js
+const Home = () => {
+ // ...
+
+ return ;
+};
+
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: Home,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+function App() {
+ return ;
+}
+```
+
+
+
+
+```js
+const Home = () => {
+ // ...
+
+ return ;
+};
+
+function App() {
+ return (
+
+
+
+ );
+}
+```
+
+
+
+
+This is not React Navigation specific, but related to React in general. You should always avoid creating components during render, whether you are using React Navigation or not.
+
+## App is not working properly when connected to Chrome Debugger
+
+When the app is connected to Chrome Debugger (or other tools that use Chrome Debugger such as [React Native Debugger](https://github.com/jhen0409/react-native-debugger)) you might encounter various issues related to timing.
+
+This can result in issues such as button presses taking a long time to register or not working at all, [gestures and animations being slow and buggy](https://github.com/facebook/react-native/issues/2367) etc. There can be other functional issues such as promises not resolving, [timeouts and intervals not working correctly](https://github.com/facebook/react-native/issues/4470) etc. as well.
+
+The issues are not related to React Navigation, but due to the nature of how the Chrome Debugger works. When connected to Chrome Debugger, your whole app runs on Chrome and communicates with the native app via sockets over the network, which can introduce latency and timing related issues.
+
+So, unless you are trying to debug something, it's better to test the app without being connected to the Chrome Debugger. If you are using iOS, you can alternatively use [Safari to debug your app](https://reactnative.dev/docs/debugging#safari-developer-tools) which debugs the app on the device directly and does not have these issues, though it has other downsides.
diff --git a/versioned_docs/version-8.x/typescript.md b/versioned_docs/version-8.x/typescript.md
new file mode 100755
index 00000000000..da1136cca14
--- /dev/null
+++ b/versioned_docs/version-8.x/typescript.md
@@ -0,0 +1,758 @@
+---
+id: typescript
+title: Type checking with TypeScript
+sidebar_label: Configuring TypeScript
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+React Navigation can be configured to type-check screens and their params, as well as various other APIs using TypeScript. This provides better intelliSense and type safety when working with React Navigation.
+
+First, make sure you have the following configuration in your `tsconfig.json` under `compilerOptions`:
+
+- `strict: true` or `strictNullChecks: true` - Necessary for intelliSense and type inference to work correctly.
+- `moduleResolution: "bundler"` - Necessary to resolve the types correctly and match the behavior of [Metro](https://metrobundler.dev/) and other bundlers.
+
+
+
+
+## Setting up the types
+
+There are 2 steps to configure TypeScript with the static API:
+
+### 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 ProfileParams = {
+ userId: string;
+ };
+ // highlight-end
+
+ // highlight-next-line
+ function ProfileScreen({ route }: StaticScreenProps) {
+ // ...
+ }
+ ```
+
+ 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
+ // highlight-next-line
+ function ProfileScreen(_: StaticScreenProps) {
+ // ...
+ }
+ ```
+
+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):
+
+ ```ts
+ linking: {
+ path: 'profile/:userId',
+ parse: {
+ userId: (id) => parseInt(id, 10),
+ },
+ },
+ ```
+
+ 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.
+
+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`
+
+See [Static configuration](static-configuration.md#createxscreen) for more details.
+
+## Using typed hooks
+
+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
+function ProfileScreen() {
+ const route = useRoute('Profile');
+
+ // The params are correctly typed here
+ const { userId } = route.params;
+
+ // ...
+}
+```
+
+With `useNavigation`:
+
+```ts
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ // Helpers like `push` are correctly typed here
+ navigation.push('Feed');
+
+ // ...
+}
+```
+
+With `useNavigationState`:
+
+```ts
+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);
+
+ // ...
+}
+```
+
+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
+
+Consider the following example:
+
+```js
+const Tab = createBottomTabNavigator();
+
+function HomeTabs() {
+ return (
+
+
+
+
+ );
+}
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeTabs,
+ },
+});
+```
+
+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 annotating the type of the [`route`](route-object.md) prop that the screen component receives:
+
+```ts
+type HomeTabsParamList = {
+ Feed: undefined;
+ Profile: undefined;
+};
+
+// highlight-start
+type HomeTabsProps = StaticScreenProps<
+ NavigatorScreenParams
+>;
+// highlight-end
+
+// highlight-next-line
+function HomeTabs(_: HomeTabsProps) {
+ return (
+
+
+
+
+ );
+}
+```
+
+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`.
+
+
+
+
+When using the dynamic API, it is necessary to specify the types for each screen as well as the nesting structure as it cannot be inferred from the code.
+
+## Typechecking the navigator
+
+To typecheck our route name and params, the first thing we need to do is to create an object type with mappings for route names to the params of the route. For example, say we have a route called `Profile` in our root navigator which should have a param `userId`:
+
+```tsx
+type RootStackParamList = {
+ Profile: { userId: string };
+};
+```
+
+Similarly, we need to do the same for each route:
+
+```tsx
+type RootStackParamList = {
+ Home: undefined;
+ Profile: { userId: string };
+ Feed: { sort: 'latest' | 'top' } | undefined;
+};
+```
+
+Specifying `undefined` means that the route doesn't have params. A union type with `undefined` (e.g. `SomeType | undefined`) means that params are optional.
+
+After we have defined the mapping, we need to tell our navigator to use it. To do that, we can pass it as a generic to the [`createXNavigator`](static-configuration.md) functions:
+
+```tsx
+import { createStackNavigator } from '@react-navigation/stack';
+
+const RootStack = createStackNavigator();
+```
+
+And then we can use it:
+
+```tsx
+
+
+
+
+
+```
+
+This will provide type checking and intelliSense for props of the [`Navigator`](navigator.md) and [`Screen`](screen.md) components.
+
+:::note
+
+The type containing the mapping must be a type alias (e.g. `type RootStackParamList = { ... }`). It cannot be an interface (e.g. `interface RootStackParamList { ... }`). It also shouldn't extend `ParamListBase` (e.g. `interface RootStackParamList extends ParamListBase { ... }`). Doing so will result in incorrect type checking which allows you to pass incorrect route names.
+
+:::
+
+## 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.
+
+For example, you can use `NativeStackScreenProps` for the Native Stack Navigator.
+
+```tsx
+import type { NativeStackScreenProps } from '@react-navigation/native-stack';
+
+type RootStackParamList = {
+ Home: undefined;
+ Profile: { userId: string };
+ Feed: { sort: 'latest' | 'top' } | undefined;
+};
+
+type Props = NativeStackScreenProps;
+```
+
+The type takes 2 generics:
+
+- The param list object we defined earlier
+- The name of the route the screen belongs to
+
+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).
+
+Similarly, you can import `StackScreenProps` from [`@react-navigation/stack`](stack-navigator.md), `DrawerScreenProps` from [`@react-navigation/drawer`](drawer-navigator.md), `BottomTabScreenProps` from [`@react-navigation/bottom-tabs`](bottom-tab-navigator.md) and so on.
+
+Then you can use the `Props` type you defined above to annotate your component.
+
+For function components:
+
+```tsx
+function ProfileScreen({ route, navigation }: Props) {
+ // ...
+}
+```
+
+For class components:
+
+```ts
+class ProfileScreen extends React.Component {
+ render() {
+ // ...
+ }
+}
+```
+
+You can get the types for `navigation` and `route` from the `Props` type as follows:
+
+```ts
+type ProfileScreenNavigationProp = Props['navigation'];
+
+type ProfileScreenRouteProp = Props['route'];
+```
+
+Alternatively, you can also annotate the `navigation` and `route` objects separately.
+
+To get the type for the `navigation` prop, we need to import the corresponding type from the navigator. For example, `NativeStackNavigationProp` for `@react-navigation/native-stack`:
+
+```tsx
+import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
+
+type ProfileScreenNavigationProp = NativeStackNavigationProp<
+ RootStackParamList,
+ 'Profile'
+>;
+```
+
+Similarly, you can import `StackNavigationProp` from [`@react-navigation/stack`](stack-navigator.md), `DrawerNavigationProp` from [`@react-navigation/drawer`](drawer-navigator.md), `BottomTabNavigationProp` from [`@react-navigation/bottom-tabs`](bottom-tab-navigator.md) etc.
+
+To get the type for the `route` object, we need to use the `RouteProp` type from `@react-navigation/native`:
+
+```tsx
+import type { RouteProp } from '@react-navigation/native';
+
+type ProfileScreenRouteProp = RouteProp;
+```
+
+We recommend creating a separate file: `types.tsx` - where you keep the types and import from there in your component files instead of repeating them in each file.
+
+## Nesting navigators
+
+### Type checking screens and params in nested navigator
+
+You can [navigate to a screen in a nested navigator](nesting-navigators.md#navigating-to-a-screen-in-a-nested-navigator) by passing `screen` and `params` properties for the nested screen:
+
+```ts
+navigation.navigate('Home', {
+ screen: 'Feed',
+ params: { sort: 'latest' },
+});
+```
+
+To be able to type check this, we need to extract the params from the screen containing the nested navigator. This can be done using the `NavigatorScreenParams` utility:
+
+```ts
+import { NavigatorScreenParams } from '@react-navigation/native';
+
+type TabParamList = {
+ Home: NavigatorScreenParams;
+ Profile: { userId: string };
+};
+```
+
+### Combining navigation props
+
+When you nest navigators, the navigation prop of the screen is a combination of multiple navigation props. For example, if we have a tab inside a stack, the `navigation` prop will have both [`jumpTo`](tab-actions.md#jumpto) (from the tab navigator) and [`push`](stack-actions.md#push) (from the stack navigator). To make it easier to combine types from multiple navigators, you can use the `CompositeScreenProps` type.
+
+For example, if we have a `Profile` in a navigator, nested inside `Account` screen of a stack navigator, we can combine the types as follows:
+
+```ts
+import type { CompositeScreenProps } from '@react-navigation/native';
+import type { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
+import type { StackScreenProps } from '@react-navigation/stack';
+
+type ProfileScreenProps = CompositeScreenProps<
+ BottomTabScreenProps,
+ StackScreenProps
+>;
+```
+
+The `CompositeScreenProps` type takes 2 parameters:
+
+- The first parameter is the type for the navigator that owns this screen, in our case the tab navigator which contains the `Profile` screen
+- The second parameter is the type of props for a parent navigator, in our case the stack navigator which contains the `Account` screen
+
+For multiple parent navigators, this second parameter can nest another `CompositeScreenProps`:
+
+```ts
+type ProfileScreenProps = CompositeScreenProps<
+ BottomTabScreenProps,
+ CompositeScreenProps<
+ StackScreenProps,
+ DrawerScreenProps
+ >
+>;
+```
+
+If annotating the `navigation` prop separately, you can use `CompositeNavigationProp` instead. The usage is similar to `CompositeScreenProps`:
+
+```ts
+import type { CompositeNavigationProp } from '@react-navigation/native';
+import type { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
+import type { StackNavigationProp } from '@react-navigation/stack';
+
+type ProfileScreenNavigationProp = CompositeNavigationProp<
+ BottomTabNavigationProp,
+ StackNavigationProp
+>;
+```
+
+## Annotating hooks
+
+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).
+
+With `useRoute`:
+
+```ts
+function ProfileScreen() {
+ const route = useRoute('Profile');
+
+ // The params are correctly typed here
+ const { userId } = route.params;
+
+ // ...
+}
+```
+
+With `useNavigation`:
+
+```ts
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+
+ // Helpers like `getState` are correctly typed here
+ const state = navigation.getState();
+
+ // ...
+}
+```
+
+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 `useNavigation` isn't type-safe because we cannot verify that the provided type matches the actual navigators.
+
+:::
+
+With `useNavigationState`:
+
+```ts
+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`
+
+When you pass the `options` to a `Screen` or `screenOptions` prop to a `Navigator` component, they are already type-checked and you don't need to do anything special. However, sometimes you might want to extract the options to a separate object, and you might want to annotate it.
+
+To annotate the options, we need to import the corresponding type from the navigator. For example, `StackNavigationOptions` for `@react-navigation/stack`:
+
+```ts
+import type { StackNavigationOptions } from '@react-navigation/stack';
+
+const options: StackNavigationOptions = {
+ headerShown: false,
+};
+```
+
+Similarly, you can import `DrawerNavigationOptions` from `@react-navigation/drawer`, `BottomTabNavigationOptions` from `@react-navigation/bottom-tabs` etc.
+
+When using the function form of `options` and `screenOptions`, you can annotate the arguments with a type exported from the navigator, e.g. `StackOptionsArgs` for `@react-navigation/stack`, `DrawerOptionsArgs` for `@react-navigation/drawer`, `BottomTabOptionsArgs` for `@react-navigation/bottom-tabs` etc.:
+
+```ts
+import type {
+ StackNavigationOptions,
+ StackOptionsArgs,
+} from '@react-navigation/stack';
+
+const options = ({ route }: StackOptionsArgs): StackNavigationOptions => {
+ return {
+ headerTitle: route.name,
+ };
+};
+```
+
+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:
+
+```ts
+import { createNavigationContainerRef } from '@react-navigation/native';
+
+// ...
+
+const navigationRef = createNavigationContainerRef();
+```
+
+Similarly, for `useNavigationContainerRef()`:
+
+```ts
+import { useNavigationContainerRef } from '@react-navigation/native';
+
+// ...
+
+const navigationRef = useNavigationContainerRef();
+```
+
+If you're using a regular `ref` object, you can pass a generic to the `NavigationContainerRef` type..
+
+Example when using `React.useRef` hook:
+
+```ts
+import type { NavigationContainerRef } from '@react-navigation/native';
+
+// ...
+
+const navigationRef =
+ React.useRef>(null);
+```
+
+Example when using `React.createRef`:
+
+```ts
+import type { NavigationContainerRef } from '@react-navigation/native';
+
+// ...
+
+const navigationRef =
+ React.createRef>();
+```
+
+## Specifying root navigator 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 use module augmentation for `@react-navigation/core` and extend the `RootNavigator` interface with the type of your root navigator.
+
+```ts
+const RootStack = createNativeStackNavigator();
+
+function App() {
+ // ...
+}
+
+// highlight-next-line
+type RootStackType = typeof RootStack;
+
+// 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
+
+When writing types for React Navigation, there are a couple of things we recommend to keep things organized.
+
+1. It's good to create a separate file (e.g. `navigation/types.tsx`) that contains the types related to React Navigation.
+2. Instead of using `CompositeNavigationProp` directly in your components, it's better to create a helper type that you can reuse.
+3. Specifying a global type for your root navigator would avoid manual annotations in many places.
+
+Considering these recommendations, the file containing the types may look something like this:
+
+```ts
+import type {
+ CompositeScreenProps,
+ NavigatorScreenParams,
+} from '@react-navigation/native';
+import type { StackScreenProps } from '@react-navigation/stack';
+import type { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
+
+export type RootStackParamList = {
+ Home: NavigatorScreenParams;
+ PostDetails: { id: string };
+ NotFound: undefined;
+};
+
+export type RootStackScreenProps =
+ StackScreenProps;
+
+export type HomeTabParamList = {
+ Popular: undefined;
+ Latest: undefined;
+};
+
+export type HomeTabScreenProps =
+ CompositeScreenProps<
+ BottomTabScreenProps,
+ RootStackScreenProps
+ >;
+```
+
+Then, you'd set up the global type for your root navigator in the same file where your root navigator is defined:
+
+```ts
+import { createStackNavigator } from '@react-navigation/stack';
+import type { RootStackParamList } from './navigation/types';
+
+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 {}
+}
+```
+
+Now, when annotating your components, you can write:
+
+```ts
+import type { HomeTabScreenProps } from './navigation/types';
+
+function PopularScreen({ navigation, route }: HomeTabScreenProps<'Popular'>) {
+ // ...
+}
+```
+
+
+
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..4a3cc81c1e4
--- /dev/null
+++ b/versioned_docs/version-8.x/upgrading-from-7.x.md
@@ -0,0 +1,789 @@
+---
+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` >= 4.19.0
+- `react-native-safe-area-context` >= 5.5.0
+- `react-native-reanimated` >= 4.0.0
+- `react-native-pager-view` >= 7.0.0 (8.0.0 is recommended)
+- `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.
+
+::: note
+
+Minimum required versions are subject to change. The minimum required version for Expo and React Native are planned to be bumped to Expo SDK 55 and React Native 0.83 respectively.
+
+:::
+
+## 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 us 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: StaticScreenConfig<
++ Linking,
++ Screen,
++ TabNavigationState,
++ MyNavigationOptions,
++ MyNavigationEventMap,
++ MyNavigationProp
++ >
++ ) {
++ 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.
+
+#### Bottom Tabs no longer shows header by default
+
+Since Bottom Tabs now renders native tabs by default, the header is no longer shown by default to match native look and feel. You can nest a [Native Stack Navigator](native-stack-navigator.md) inside each tab to show a header that integrates well with native tabs, e.g. [search tab on iOS 26+](bottom-tab-navigator.md#search-tab-on-ios-26).
+
+Alternatively, you can enable the built-in header by passing `headerShown: true` in `screenOptions` of the navigator:
+
+
+
+
+```diff lang=js
+createBottomTabNavigator({
+ screenOptions: {
++ headerShown: true,
+ // ...
+ },
+ // ...
+});
+```
+
+
+
+
+```diff lang=js
+
+```
+
+
+
+
+#### 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.
+
+#### Various components no longer receive layout related props
+
+Previously, various components such as `Header`, `BottomTabBar`, and `DrawerContent` received layout related props such as `layout` - that contained the dimensions of the screen.
+
+This meant that if the `layout` changed frequently, such as resizing the window on supported platforms (Web, Windows, macOS, iPadOS), it would need to re-render these components frequently - often not being able to keep up with the changes, leading to jank and poor performance.
+
+To avoid this, we have removed layout related props from these components:
+
+- `layout` prop from `Header` component from `@react-navigation/elements`
+- `titleLayout` and `screenLayout` props from `HeaderBackButton` component from `@react-navigation/elements`
+- `layouts.title` and `layouts.leftLabel` parameters from `headerStyleInterpolator` in `@react-navigation/stack`
+- `layout` prop from `react-native-tab-view`
+- `layout` prop from `react-native-drawer-layout`
+
+Since React Native doesn't provide APIs to handle layout changes in styles, it may still be necessary to handle layout changes manually in some cases. So we have added a [`useFrameSize`](elements.md#useframesize) hook that takes a selector function to minimize re-renders:
+
+```js
+import { useFrameSize } from '@react-navigation/elements';
+
+// ...
+
+const isLandscape = useFrameSize((size) => size.width > size.height);
+```
+
+#### 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;
+ // ...
+ },
+ },
+ },
+ },
+ },
+});
+```
+
+
+
+
+```diff lang=js
+
+ {
++ 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.
+
+#### Stack Navigator now accepts a number for `gestureResponseDistance`
+
+Previously, the `gestureResponseDistance` option in Stack Navigator accepted an object with `horizontal` and `vertical` properties to specify the distance for gestures. Since it's not pssible to have both horizontal and vertical gestures at the same time, it now accepts a number to specify the distance for the current gesture direction:
+
+```diff lang=js
+- gestureResponseDistance: { horizontal: 50 }
++ gestureResponseDistance: 50
+```
+
+#### 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.
+
+### Deep linking to screens behind conditional screens is now supported
+
+Previously, if a screen was conditionally rendered based on some state (e.g. authentication status), deep linking to that screen wouldn't work since the screen wouldn't exist in the navigator when the app was opened via a deep link.
+
+In React Navigation 7, we added an experimental `UNSTABLE_routeNamesChangeBehavior` option to enable remembering such unhandled actions and re-attempting them when the list of route names changed after the conditions changed by setting the option to `lastUnhandled`.
+
+In React Navigation 8, we have dropped the `UNSTABLE_` prefix and made it a stable API.
+
+```js static2dynamic
+const Stack = createNativeStackNavigator({
+ // highlight-start
+ routeNamesChangeBehavior: 'lastUnhandled',
+ // highlight-end
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+```
+
+### 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
new file mode 100755
index 00000000000..ec6d7aae01d
--- /dev/null
+++ b/versioned_docs/version-8.x/use-focus-effect.md
@@ -0,0 +1,191 @@
+---
+id: use-focus-effect
+title: useFocusEffect
+sidebar_label: useFocusEffect
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+Sometimes we want to run side-effects when a screen is focused. A side effect may involve things like adding an event listener, fetching data, updating document title, etc. While this can be achieved using `focus` and `blur` events, it's not very ergonomic.
+
+To make this easier, the library exports a `useFocusEffect` hook:
+
+```js name="useFocusEffect hook" snack static2dynamic
+import * as React from 'react';
+import { View } from 'react-native';
+import { createStaticNavigation } from '@react-navigation/native';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+// codeblock-focus-start
+import { useFocusEffect } from '@react-navigation/native';
+
+function ProfileScreen() {
+ useFocusEffect(
+ React.useCallback(() => {
+ // Do something when the screen is focused
+ return () => {
+ // Do something when the screen is unfocused
+ // Useful for cleanup functions
+ };
+ }, [])
+ );
+
+ return ;
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ return ;
+}
+
+const MyTabs = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTabs);
+
+export default function App() {
+ return ;
+}
+```
+
+:::warning
+
+To avoid the running the effect too often, it's important to wrap the callback in `useCallback` before passing it to `useFocusEffect` as shown in the example.
+
+:::
+
+The `useFocusEffect` is analogous to React's `useEffect` hook. The only difference is that it only runs if the screen is currently focused.
+
+The effect will run whenever the dependencies passed to `React.useCallback` change, i.e. it'll run on initial render (if the screen is focused) as well as on subsequent renders if the dependencies have changed. If you don't wrap your effect in `React.useCallback`, the effect will run every render if the screen is focused.
+
+The cleanup function runs when the previous effect needs to be cleaned up, i.e. when dependencies change and a new effect is scheduled and when the screen unmounts or blurs.
+
+## Running asynchronous effects
+
+When running asynchronous effects such as fetching data from server, it's important to make sure that you cancel the request in the cleanup function (similar to `React.useEffect`). If you're using an API that doesn't provide a cancellation mechanism, make sure to ignore the state updates:
+
+```js
+useFocusEffect(
+ React.useCallback(() => {
+ let isActive = true;
+
+ const fetchUser = async () => {
+ try {
+ const user = await API.fetch({ userId });
+
+ if (isActive) {
+ setUser(user);
+ }
+ } catch (e) {
+ // Handle error
+ }
+ };
+
+ fetchUser();
+
+ return () => {
+ isActive = false;
+ };
+ }, [userId])
+);
+```
+
+If you don't ignore the result, then you might end up with inconsistent data due to race conditions in your API calls.
+
+## Delaying effect until transition finishes
+
+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.
+
+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 unsubscribe = navigation.addListener('transitionEnd', () => {
+ // Expensive task after transition finishes
+ });
+
+ 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.
+
+The `useFocusEffect` allows you to run an effect on focus and clean it up when the screen becomes unfocused. It also handles cleanup on unmount. It re-runs the effect when dependencies change, so you don't need to worry about stale values in your listener.
+
+## When to use `focus` and `blur` events instead
+
+Like `useEffect`, a cleanup function can be returned from the effect in `useFocusEffect`. The cleanup function is intended to cleanup the effect - e.g. abort an asynchronous task, unsubscribe from an event listener, etc. It's not intended to be used to do something on `blur`.
+
+For example, **don't do the following**:
+
+```js
+useFocusEffect(
+ React.useCallback(() => {
+ return () => {
+ // Do something that should run on blur
+ };
+ }, [])
+);
+```
+
+The cleanup function runs whenever the effect needs to cleanup, i.e. on `blur`, unmount, dependency change etc. It's not a good place to update the state or do something that should happen on `blur`. You should use listen to the `blur` event instead:
+
+```js
+React.useEffect(() => {
+ const unsubscribe = navigation.addListener('blur', () => {
+ // Do something when the screen blurs
+ });
+
+ return unsubscribe;
+}, [navigation]);
+```
+
+Similarly, if you want to do something when the screen receives focus (e.g. track screen focus) and it doesn't need cleanup or need to be re-run on dependency changes, then you should use the `focus` event instead:
+
+## Using with class component
+
+You can make a component for your effect and use it in your class component:
+
+```js
+function FetchUserData({ userId, onUpdate }) {
+ useFocusEffect(
+ React.useCallback(() => {
+ const unsubscribe = API.subscribe(userId, onUpdate);
+
+ return () => unsubscribe();
+ }, [userId, onUpdate])
+ );
+
+ return null;
+}
+
+// ...
+
+class Profile extends React.Component {
+ _handleUpdate = (user) => {
+ // Do something with user object
+ };
+
+ render() {
+ return (
+ <>
+
+ {/* rest of your code */}
+ >
+ );
+ }
+}
+```
diff --git a/versioned_docs/version-8.x/use-is-focused.md b/versioned_docs/version-8.x/use-is-focused.md
new file mode 100755
index 00000000000..9b2aa385145
--- /dev/null
+++ b/versioned_docs/version-8.x/use-is-focused.md
@@ -0,0 +1,71 @@
+---
+id: use-is-focused
+title: useIsFocused
+sidebar_label: useIsFocused
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+We might want to render different content based on the current focus state of the screen. The library exports a `useIsFocused` hook to make this easier:
+
+```js name="useIsFocused hook" snack static2dynamic
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { createStaticNavigation } from '@react-navigation/native';
+import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+// codeblock-focus-start
+import { useIsFocused } from '@react-navigation/native';
+
+function ProfileScreen() {
+ // This hook returns `true` if the screen is focused, `false` otherwise
+ // highlight-next-line
+ const isFocused = useIsFocused();
+
+ return (
+
+ {isFocused ? 'focused' : 'unfocused'}
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ return ;
+}
+
+const MyTabs = createMaterialTopTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTabs);
+
+export default function App() {
+ return ;
+}
+```
+
+Note that using this hook triggers a re-render for the component when the screen it's in changes focus. This might cause lags during the animation if your component is heavy. You might want to extract the expensive parts to separate components and use [`React.memo`](https://react.dev/reference/react/memo) or [`React.PureComponent`](https://react.dev/reference/react/PureComponent) to minimize re-renders for them.
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class Profile extends React.Component {
+ render() {
+ // Get it from props
+ const { isFocused } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const isFocused = useIsFocused();
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-link-builder.md b/versioned_docs/version-8.x/use-link-builder.md
new file mode 100644
index 00000000000..dcb3da963f7
--- /dev/null
+++ b/versioned_docs/version-8.x/use-link-builder.md
@@ -0,0 +1,64 @@
+---
+id: use-link-builder
+title: useLinkBuilder
+sidebar_label: useLinkBuilder
+---
+
+The `useLinkBuilder` hook returns helpers to build `href` or action based on the [`linking` configuration](configuring-links.md). It returns an object with the following properties:
+
+- [`buildHref`](#buildhref)
+- [`buildAction`](#buildaction)
+
+## `buildHref`
+
+The `buildHref` method lets us build a path to use for links for a screen in the current navigator's state. It returns a function that takes `name` and `params` for the screen to focus and returns path based on the [`linking` configuration](configuring-links.md).
+
+```js
+import { useLinkBuilder } from '@react-navigation/native';
+import { PlatformPressable } from '@react-navigation/elements';
+
+// ...
+
+function DrawerContent({ state, descriptors, navigation }) {
+ const { buildHref } = useLinkBuilder();
+
+ return state.routes((route) => (
+ navigation.navigate(route.name, route.params)}
+ >
+ {descriptors[route.key].options.title}
+
+ ));
+}
+```
+
+This hook is intended to be used in navigators to show links to various pages in the navigator, such as drawer and tab navigators. If you're building a custom navigator, custom drawer content, custom tab bar etc. then you might want to use this hook.
+
+There are couple of important things to note:
+
+- The destination screen must be present in the current navigator. It cannot be in a parent navigator or a navigator nested in a child.
+- It's intended to be only used in custom navigators to keep them reusable in multiple apps. For your regular app code, use screen names directly instead of building paths for screens.
+
+## `buildAction`
+
+The `buildAction` method lets us parse a `href` string into an action object that can be used with [`navigation.dispatch`](navigation-object.md#dispatch) to navigate to the relevant screen.
+
+```js
+import { Link, CommonActions, useLinkBuilder } from '@react-navigation/native';
+import { Button } from '@react-navigation/elements';
+
+// ...
+
+function MyComponent() {
+ const { buildAction } = useLinkBuilder();
+
+ return (
+ navigation.dispatch(buildAction('/users/jane'))}>
+ Go to Jane's profile
+
+ );
+}
+```
+
+The [`useLinkTo`](use-link-to.md) hook is a convenient wrapper around this hook to navigate to a screen using a `href` string.
diff --git a/versioned_docs/version-8.x/use-link-props.md b/versioned_docs/version-8.x/use-link-props.md
new file mode 100644
index 00000000000..9a1834fa9ce
--- /dev/null
+++ b/versioned_docs/version-8.x/use-link-props.md
@@ -0,0 +1,110 @@
+---
+id: use-link-props
+title: useLinkProps
+sidebar_label: useLinkProps
+---
+
+The `useLinkProps` hook lets us build our custom link component. The link component can be used as a button to navigate to a screen. On the web, it will be rendered as an anchor tag (``) with the `href` attribute so that all the accessibility features of a link are preserved, e.g. - such as `Right click -> Open link in new tab"`, `Ctrl+Click`/`⌘+Click` etc.
+
+It returns an object with some props that you can pass to a component.
+
+Example:
+
+```js
+import { useLinkProps } from '@react-navigation/native';
+
+// ...
+
+const LinkButton = ({ screen, params, action, href, children, ...rest }) => {
+ const props = useLinkProps({ screen, params, action, href });
+
+ const [isHovered, setIsHovered] = React.useState(false);
+
+ return (
+
+ {children}
+
+ );
+};
+```
+
+Then you can use the `LinkButton` component elsewhere in your app:
+
+```js
+function Home() {
+ return (
+
+ Go to Jane's profile
+
+ );
+}
+```
+
+## Options
+
+### `screen` and `params`
+
+You can pass `screen` and `params` to navigate to a screen on press:
+
+```js
+function Home() {
+ return (
+
+ Go to Jane's profile
+
+ );
+}
+```
+
+If you want to navigate to a nested screen, you can pass the name of the `screen` in `params` similar to [navigating to a screen in a nested navigator](nesting-navigators.md#navigating-to-a-screen-in-a-nested-navigator):
+
+```js
+
+ Go to post 123
+
+```
+
+### `action`
+
+Sometimes we want a different behavior for in-page navigation, such as `replace` instead of `navigate`. We can use the `action` prop to customize it:
+
+Example:
+
+```js
+import { StackActions } from '@react-navigation/native';
+
+// ...
+
+function Home() {
+ return (
+
+ Go to Jane's profile
+
+ );
+}
+```
+
+The `screen` and `params` props can be omitted if the `action` prop is specified. In that case, we recommend specifying the `href` prop as well to ensure that the link is accessible.
+
+### `href`
+
+The `href` is used for the `href` attribute of the anchor tag on the Web to make the links accessible. By default, this is automatically determined based on the [`linking` options](navigation-container.md#linking) using the `screen` and `params` props.
+
+If you want to use a custom `href`, you can pass it as the `href` prop:
+
+```js
+function Home() {
+ return (
+
+ Getting Started
+
+ );
+}
+```
diff --git a/versioned_docs/version-8.x/use-link-to.md b/versioned_docs/version-8.x/use-link-to.md
new file mode 100644
index 00000000000..e75da45d473
--- /dev/null
+++ b/versioned_docs/version-8.x/use-link-to.md
@@ -0,0 +1,51 @@
+---
+id: use-link-to
+title: useLinkTo
+sidebar_label: useLinkTo
+---
+
+The `useLinkTo` hook lets us navigate to a screen using a path instead of a screen name based on the [`linking` options](navigation-container.md#linking). It returns a function that receives the path to navigate to.
+
+```js
+import { useLinkTo } from '@react-navigation/native';
+
+// ...
+
+function Home() {
+ const linkTo = useLinkTo();
+
+ return (
+ linkTo('/profile/jane')}>
+ Go to Jane's profile
+
+ );
+}
+```
+
+This is a low-level hook used to build more complex behavior on top. We recommended using the [`useLinkProps` hook](use-link-props.md) to build your custom link components instead of using this hook directly. It will ensure that your component is properly accessible on the web.
+
+:::warning
+
+Navigating via `href` strings is not type-safe. If you want to navigate to a screen with type-safety, it's recommended to use screen names directly.
+
+:::
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class Home extends React.Component {
+ render() {
+ // Get it from props
+ const { linkTo } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const linkTo = useLinkTo();
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-navigation-state.md b/versioned_docs/version-8.x/use-navigation-state.md
new file mode 100755
index 00000000000..897e57d5c57
--- /dev/null
+++ b/versioned_docs/version-8.x/use-navigation-state.md
@@ -0,0 +1,240 @@
+---
+id: use-navigation-state
+title: useNavigationState
+sidebar_label: useNavigationState
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+`useNavigationState` is a hook which gives access to the [navigation state](navigation-state.md) of the navigator which contains the screen. It's useful in rare cases where you want to render something based on the navigation state.
+
+:::warning
+
+Consider the navigator's state object to be internal and subject to change in a minor release. Avoid using properties from the [navigation state](navigation-state.md) state object except `index` and `routes`, unless you really need it. If there is some functionality you cannot achieve without relying on the structure of the state object, please open an issue.
+
+:::
+
+It can be used in two ways.
+
+## 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('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.
+
+:::
+
+## How is `useNavigationState` different from `navigation.getState()`?
+
+The `navigation.getState()` function also returns the current [navigation state](navigation-state.md). The main difference is that the `useNavigationState` hook will trigger a re-render when values change, while `navigation.getState()` won't. For example, the following code will be incorrect:
+
+```js
+function Profile() {
+ const routesLength = navigation.getState().routes.length; // Don't do this
+
+ return Number of routes: {routesLength} ;
+}
+```
+
+In this example, even if you push a new screen, this text won't update. If you use the hook, it'll work as expected:
+
+```js name="useNavigation hook" snack static2dynamic
+import * as React from 'react';
+import { Button } from '@react-navigation/elements';
+import { View, Text } from 'react-native';
+import {
+ createStaticNavigation,
+ useNavigation,
+ useRoute,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+// codeblock-focus-start
+import { useNavigationState } from '@react-navigation/native';
+
+function useIsFirstRouteInParent() {
+ const route = useRoute();
+ const isFirstRouteInParent = useNavigationState(
+ (state) => state.routes[0].key === route.key
+ );
+
+ return isFirstRouteInParent;
+}
+
+function usePreviousRouteName() {
+ return useNavigationState((state) =>
+ state.routes[state.index - 1]?.name
+ ? state.routes[state.index - 1].name
+ : 'None'
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const isFirstRoute = useIsFirstRouteInParent();
+ const previousRouteName = usePreviousRouteName();
+
+ return (
+
+ It is {isFirstRoute ? '' : 'not '}first route in navigator
+ Previous route name: {previousRouteName}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const navigation = useNavigation('Profile');
+ const isFirstRoute = useIsFirstRouteInParent();
+ const previousRouteName = usePreviousRouteName();
+
+ return (
+
+ It is {isFirstRoute ? '' : 'not '}first route in navigator
+ Previous route name: {previousRouteName}
+ navigation.navigate('Settings')}>
+ Go to Settings
+
+ navigation.goBack()}>Go back
+
+ );
+}
+
+function SettingsScreen() {
+ const navigation = useNavigation('Settings');
+ const isFirstRoute = useIsFirstRouteInParent();
+ const previousRouteName = usePreviousRouteName();
+
+ return (
+
+ It is {isFirstRoute ? '' : 'not '}first route in navigator
+ Previous route name: {previousRouteName}
+ navigation.goBack()}>Go back
+
+ );
+}
+
+const RootStack = createNativeStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+```
+
+So when do you use `navigation.getState()`? It's mostly useful within event listeners where you don't care about what's rendered. In most cases, using the hook should be preferred.
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class Profile extends React.Component {
+ render() {
+ // Get it from props
+ const { routesLength } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const routesLength = useNavigationState((state) => state.routes.length);
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-navigation.md b/versioned_docs/version-8.x/use-navigation.md
new file mode 100755
index 00000000000..100f3070272
--- /dev/null
+++ b/versioned_docs/version-8.x/use-navigation.md
@@ -0,0 +1,116 @@
+---
+id: use-navigation
+title: useNavigation
+sidebar_label: useNavigation
+---
+
+import Tabs from '@theme/Tabs';
+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.
+
+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';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import { createStaticNavigation } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+// codeblock-focus-start
+import { useNavigation } from '@react-navigation/native';
+
+function MyBackButton() {
+ // highlight-next-line
+ const navigation = useNavigation('Profile');
+
+ return (
+ {
+ navigation.goBack();
+ }}
+ >
+ Back
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ This is the home screen of the app
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ return (
+
+ Profile Screen
+
+
+ );
+}
+
+const RootStack = createNativeStackNavigator({
+ initialRouteName: 'Home',
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+function App() {
+ return ;
+}
+
+export default App;
+```
+
+## 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.
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class MyBackButton extends React.Component {
+ render() {
+ // Get it from props
+ const { navigation } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const navigation = useNavigation();
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-prevent-remove.md b/versioned_docs/version-8.x/use-prevent-remove.md
new file mode 100644
index 00000000000..1e9eac665cd
--- /dev/null
+++ b/versioned_docs/version-8.x/use-prevent-remove.md
@@ -0,0 +1,158 @@
+---
+id: use-prevent-remove
+title: usePreventRemove
+sidebar_label: usePreventRemove
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+The `usePreventRemove` hook allows you to prevent the user from leaving a screen. For example, if there are unsaved changes, you might want to show a confirmation dialog before the user can navigate away.
+
+The hook takes 2 parameters:
+
+- `preventRemove`: A boolean value indicating whether to prevent the screen from being removed.
+- `callback`: A function that will be called when the removal is prevented. This can be used to show a confirmation dialog.
+
+The callback receives a `data` object with the `action` that triggered the removal of the screen. You can dispatch this action again after confirmation, or check the action object to determine what to do.
+
+Example:
+
+```js name="usePreventRemove hook" snack static2dynamic
+import * as React from 'react';
+import { Alert, View, TextInput, Platform, StyleSheet } from 'react-native';
+import {
+ useNavigation,
+ usePreventRemove,
+ createStaticNavigation,
+} from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+import { Button } from '@react-navigation/elements';
+
+// codeblock-focus-start
+const EditTextScreen = () => {
+ const [text, setText] = React.useState('');
+ const navigation = useNavigation('EditText');
+
+ const hasUnsavedChanges = Boolean(text);
+
+ usePreventRemove(hasUnsavedChanges, ({ data }) => {
+ if (Platform.OS === 'web') {
+ const discard = confirm(
+ 'You have unsaved changes. Discard them and leave the screen?'
+ );
+
+ if (discard) {
+ navigation.dispatch(data.action);
+ }
+ } else {
+ Alert.alert(
+ 'Discard changes?',
+ 'You have unsaved changes. Discard them and leave the screen?',
+ [
+ { text: "Don't leave", style: 'cancel', onPress: () => {} },
+ {
+ text: 'Discard',
+ style: 'destructive',
+ onPress: () => navigation.dispatch(data.action),
+ },
+ ]
+ );
+ }
+ });
+
+ return (
+
+
+
+ );
+};
+// codeblock-focus-end
+
+const HomeScreen = () => {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ navigation.push('EditText')} style={styles.button}>
+ Push EditText
+
+
+ );
+};
+
+const RootStack = createStackNavigator({
+ screens: {
+ Home: HomeScreen,
+ EditText: EditTextScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+export default function App() {
+ return ;
+}
+
+const styles = StyleSheet.create({
+ content: {
+ flex: 1,
+ padding: 16,
+ },
+ input: {
+ margin: 8,
+ padding: 10,
+ borderRadius: 3,
+ borderWidth: StyleSheet.hairlineWidth,
+ borderColor: 'rgba(0, 0, 0, 0.08)',
+ backgroundColor: 'white',
+ },
+ buttons: {
+ flex: 1,
+ justifyContent: 'center',
+ padding: 8,
+ },
+ button: {
+ margin: 8,
+ },
+});
+```
+
+
+
+
+
+Internally, the hook uses the [`beforeRemove`](navigation-events.md#beforeremove) event to prevent the screen from being removed. This event is triggered whenever a screen is being removed due to a navigation action.
+
+## Limitations
+
+There are a couple of limitations to be aware of when using the `usePreventRemove` hook. It is **only** triggered whenever a screen is being removed due to a navigation state change. For example:
+
+- The user pressed the back button on a screen in a stack.
+- The user performed a swipe-back gesture.
+- Some action such as `pop` or `reset` was dispatched which removes the screen from the state.
+
+It **does not prevent** a screen from being unfocused if it's not being removed. For example:
+
+- The user pushed a new screen on top of the screen with the listener in a stack.
+- The user navigated from one tab/drawer screen to another tab/drawer screen.
+
+It also **does not prevent** a screen from being removed when the user is exiting the screen due to actions not controlled by the navigation state:
+
+- The user closes the app (e.g. by pressing the back button on the home screen, closing the tab in the browser, closing it from the app switcher etc.). You can additionally use [`hardwareBackPress`](https://reactnative.dev/docs/backhandler) event on Android, [`beforeunload`](https://developer.mozilla.org/en-US/docs/web/api/window/beforeunload_event) event on the Web etc. to handle some of these cases. See [Prevent the user from leaving the app](preventing-going-back.md#prevent-the-user-from-leaving-the-app) for more details.
+- A screen gets unmounted due to conditional rendering, or due to a parent component being unmounted.
+
+## UX considerations
+
+Generally, we recommend using this hook sparingly. A better approach is to persist the unsaved data into [`AsyncStorage`](https://github.com/react-native-async-storage/async-storage) or similar persistent storage and prompt to restore it when the user returns to the screen.
+
+Doing so has several benefits:
+
+- This approach still works if the app is closed or crashes unexpectedly.
+- It's less intrusive to the user as they can still navigate away from the screen to check something and return without losing the data.
diff --git a/versioned_docs/version-8.x/use-route-path.md b/versioned_docs/version-8.x/use-route-path.md
new file mode 100644
index 00000000000..530bc324cb7
--- /dev/null
+++ b/versioned_docs/version-8.x/use-route-path.md
@@ -0,0 +1,25 @@
+---
+id: use-route-path
+title: useRoutePath
+sidebar_label: useRoutePath
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+The `useRoutePath` hook can be used to get the path of a route based on the [`linking` configuration](configuring-links.md). This can be useful if you need to generate a URL for a specific route in your app to share as a deep link.
+
+## Example
+
+```js
+import { useRoutePath } from '@react-navigation/native';
+
+function MyComponent() {
+ const path = useRoutePath();
+
+ // Construct a URL using the path and app's base URL
+ const url = new URL(path, 'https://example.com');
+
+ return Shareable URL: {url.href} ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-route.md b/versioned_docs/version-8.x/use-route.md
new file mode 100755
index 00000000000..1f2cf2fc681
--- /dev/null
+++ b/versioned_docs/version-8.x/use-route.md
@@ -0,0 +1,115 @@
+---
+id: use-route
+title: useRoute
+sidebar_label: useRoute
+---
+
+import Tabs from '@theme/Tabs';
+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.
+
+It can be used in two ways.
+
+## 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';
+import { View, Text } from 'react-native';
+import { Button } from '@react-navigation/elements';
+import {
+ createStaticNavigation,
+ useNavigation,
+} from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+// codeblock-focus-start
+import { useRoute } from '@react-navigation/native';
+
+function MyText() {
+ // highlight-next-line
+ const route = useRoute('Profile');
+
+ return {route.params.caption} ;
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+
+ return (
+
+ This is the home screen of the app
+ {
+ navigation.navigate('Profile', { caption: 'Some caption' });
+ }}
+ >
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ return (
+
+ Profile Screen
+
+
+ );
+}
+
+const RootStack = createNativeStackNavigator({
+ initialRouteName: 'Home',
+ screens: {
+ Home: HomeScreen,
+ Profile: ProfileScreen,
+ },
+});
+
+const Navigation = createStaticNavigation(RootStack);
+
+function App() {
+ return ;
+}
+
+export default App;
+```
+
+## 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.
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class MyText extends React.Component {
+ render() {
+ // Get it from props
+ const { route } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const route = useRoute('Profile');
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-scroll-to-top.md b/versioned_docs/version-8.x/use-scroll-to-top.md
new file mode 100755
index 00000000000..9c714c15cbf
--- /dev/null
+++ b/versioned_docs/version-8.x/use-scroll-to-top.md
@@ -0,0 +1,169 @@
+---
+id: use-scroll-to-top
+title: useScrollToTop
+sidebar_label: useScrollToTop
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+The expected native behavior of scrollable components is to respond to events from navigation that will scroll to top when tapping on the active tab as you would expect from native tab bars.
+
+In order to achieve it we export `useScrollToTop` which accept ref to scrollable component (e,g. `ScrollView` or `FlatList`).
+
+Example:
+
+```js name="useScrollToTop hook" snack static2dynamic
+import * as React from 'react';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createStaticNavigation } from '@react-navigation/native';
+import { View, Image } from 'react-native';
+// codeblock-focus-start
+import { ScrollView } from 'react-native';
+import { useScrollToTop } from '@react-navigation/native';
+
+function Albums() {
+ const ref = React.useRef(null);
+
+ // highlight-next-line
+ useScrollToTop(ref);
+
+ return (
+
+ {/* content */}
+ // codeblock-focus-end
+
+
+
+
+ // codeblock-focus-start
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ return ;
+}
+
+const MyTabs = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Albums: Albums,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTabs);
+
+export default function App() {
+ return ;
+}
+```
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class Albums extends React.Component {
+ render() {
+ return {/* content */} ;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const ref = React.useRef(null);
+
+ useScrollToTop(ref);
+
+ return ;
+}
+```
+
+## Providing scroll offset
+
+If you require offset to scroll position you can wrap and decorate passed reference:
+
+```js name="useScrollToTop hook - providing scroll offset" snack static2dynamic
+import * as React from 'react';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { View, Image } from 'react-native';
+import { createStaticNavigation } from '@react-navigation/native';
+
+// codeblock-focus-start
+import { ScrollView } from 'react-native';
+import { useScrollToTop } from '@react-navigation/native';
+
+function Albums() {
+ const ref = React.useRef(null);
+
+ useScrollToTop(
+ React.useRef({
+ scrollToTop: () => ref.current?.scrollTo({ y: 100 }),
+ })
+ );
+
+ return (
+
+ {/* content */}
+ // codeblock-focus-end
+
+
+
+
+ // codeblock-focus-start
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ return ;
+}
+
+const MyTab = createBottomTabNavigator({
+ screens: {
+ Home: HomeScreen,
+ Albums: Albums,
+ },
+});
+
+const Navigation = createStaticNavigation(MyTab);
+
+export default function App() {
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/use-theme.md b/versioned_docs/version-8.x/use-theme.md
new file mode 100644
index 00000000000..fed51e5efa0
--- /dev/null
+++ b/versioned_docs/version-8.x/use-theme.md
@@ -0,0 +1,140 @@
+---
+id: use-theme
+title: useTheme
+sidebar_label: useTheme
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+The `useTheme` hook lets us access the currently active theme. You can use it in your own components to have them respond to changes in the theme.
+
+```js name="useTheme hook" snack static2dynamic
+import * as React from 'react';
+import {
+ useNavigation,
+ createStaticNavigation,
+ DefaultTheme,
+ DarkTheme,
+} from '@react-navigation/native';
+import { View, Text, TouchableOpacity, useColorScheme } from 'react-native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import { createDrawerNavigator } from '@react-navigation/drawer';
+import { Button } from '@react-navigation/elements';
+// codeblock-focus-start
+import { useTheme } from '@react-navigation/native';
+
+// codeblock-focus-end
+
+function SettingsScreen({ route }) {
+ const navigation = useNavigation('Settings');
+ const { user } = route.params;
+ const { colors } = useTheme();
+
+ return (
+
+ Settings Screen
+
+ userParam: {JSON.stringify(user)}
+
+ navigation.navigate('Profile')}>
+ Go to Profile
+
+
+ );
+}
+
+function ProfileScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ Profile Screen
+
+ );
+}
+
+// codeblock-focus-start
+function MyButton() {
+ // highlight-next-line
+ const { colors } = useTheme();
+
+ return (
+
+ Button!
+
+ );
+}
+// codeblock-focus-end
+
+function HomeScreen() {
+ const navigation = useNavigation('Home');
+ const { colors } = useTheme();
+
+ return (
+
+ Home Screen
+
+
+ navigation.navigate('Root', {
+ screen: 'Settings',
+ params: { user: 'jane' },
+ })
+ }
+ >
+ Go to Settings
+
+
+ );
+}
+
+const PanelStack = createNativeStackNavigator({
+ screens: {
+ Profile: ProfileScreen,
+ Settings: SettingsScreen,
+ },
+});
+
+const MyDrawer = createDrawerNavigator({
+ initialRouteName: 'Panel',
+ screens: {
+ Home: HomeScreen,
+ Panel: {
+ screen: PanelStack,
+ options: {
+ headerShown: false,
+ },
+ },
+ },
+});
+
+const Navigation = createStaticNavigation(MyDrawer);
+
+export default function App() {
+ const scheme = useColorScheme();
+ return ;
+}
+```
+
+See [theming guide](themes.md) for more details and usage guide around how to configure themes.
+
+## Using with class component
+
+You can wrap your class component in a function component to use the hook:
+
+```js
+class MyButton extends React.Component {
+ render() {
+ // Get it from props
+ const { theme } = this.props;
+ }
+}
+
+// Wrap and export
+export default function (props) {
+ const theme = useTheme();
+
+ return ;
+}
+```
diff --git a/versioned_docs/version-8.x/used-by.md b/versioned_docs/version-8.x/used-by.md
new file mode 100644
index 00000000000..e2eb210758c
--- /dev/null
+++ b/versioned_docs/version-8.x/used-by.md
@@ -0,0 +1,55 @@
+---
+id: used-by
+title: Apps using React Navigation
+sidebar_label: Apps using React Navigation
+---
+
+It's impossible to list every single app that uses React Navigation, but below are some of the great apps that we have found that make us feel humbled and proud!
+
+## Selected highlights
+
+- [Bloomberg](https://www.bloombergapps.com/app/bloomberg/)
+- [Brex](https://brex.com/mobile/)
+- [COVID Symptom Study](https://covid.joinzoe.com/)
+- [Call of Duty companion app](https://www.callofduty.com/app)
+- [Codecademy Go](https://www.codecademy.com/mobile-app-download)
+- [Coinbase Pro](https://pro.coinbase.com/)
+- [DataCamp](https://www.datacamp.com/mobile/)
+- [Expo](https://expo.io/client)
+- [How We Feel](https://howwefeel.org/)
+- [National Football League (NFL)](https://itunes.apple.com/app/nfl/id389781154) and [NFL Fantasy Football](https://apps.apple.com/us/app/nfl-fantasy-football/id876054082)
+- [Playstation App](https://www.playstation.com/en-ca/playstation-app/) ([iOS](https://apps.apple.com/us/app/playstation-app/id410896080)) ([Android](https://play.google.com/store/apps/details?id=com.scee.psxandroid&hl=en_CA&gl=US))
+- [Readwise](https://readwise.io/)
+- [Shop from Shopify](https://www.shopify.com/shop)
+- [Steady](https://steadyapp.com/) ([iOS](https://apps.apple.com/us/app/id1339259265)) ([Android](https://play.google.com/store/apps/details?id=com.steady.steadyapp.com))
+- [TaskRabbit](https://apps.apple.com/ca/app/taskrabbit-handyman-more/id374165361)
+- [Th3rdwave](https://www.th3rdwave.coffee/)
+
+## Other great apps
+
+- [1000Kitap](https://1000kitap.com/) ([iOS](https://apps.apple.com/tr/app/1000kitap/id1319837589?l=tr)) ([Android](https://play.google.com/store/apps/details?id=com.binkitap.android&hl=en))
+- [ActiveCollab](https://activecollab.com/) ([iOS](https://apps.apple.com/us/app/activecollab-work-management/id1509421965)) ([Android](https://play.google.com/store/apps/details?id=com.activecollab.mobile))
+- [Cameo](https://apps.apple.com/us/app/cameo-personal-celeb-videos/id1258311581)
+- [COVID Shield](https://www.covidshield.app/) ([Source Code](https://github.com/CovidShield/mobile))
+- [CuppaZee](https://www.cuppazee.app/) ([Source Code](https://github.com/CuppaZee/CuppaZee)) ([iOS](https://apps.apple.com/us/app/cuppazee/id1514563308)) ([Android](https://play.google.com/store/apps/details?id=uk.cuppazee.paper))
+- [Driversnote](https://www.driversnote.com/)
+- [Disprz](https://www.disprz.com/) ([iOS](https://apps.apple.com/us/app/disprz/id1458716803#?platform=iphone)) ([Android](https://play.google.com/store/apps/details?id=com.disprz&hl=en_IN&gl=US))
+- [Fin](https://tryfin.app/)
+- [JustCash](https://justcash.app/) ([Android](https://play.google.com/store/apps/details?id=com.justcash&hl=en&gl=US))
+- [NMF.earth](https://nmf.earth/) ([Source Code](https://github.com/NMF-earth/nmf-app)) ([iOS](https://apps.apple.com/us/app/nmf-earth/id1494561829)) ([Android](https://play.google.com/store/apps/details?id=nmf.earth))
+- [Pickyourtrail](https://apps.apple.com/us/app/pickyourtrail/id1400253672)
+- [Prep: University Companion](https://prep.surf) ([iOS](http://tiny.cc/q4lliz)) ([Android](http://tiny.cc/14lliz)) ([Web](https://app.prep.surf/))
+- [Rocket.Chat](https://rocket.chat/) ([Source Code](https://github.com/RocketChat/Rocket.Chat.ReactNative)) ([iOS](https://apps.apple.com/us/app/rocket-chat/id1148741252)) ([Android](https://play.google.com/store/apps/details?id=chat.rocket.android))
+- [Saffron](https://www.mysaffronapp.com/) ([iOS](https://apps.apple.com/us/app/saffron-your-digital-cookbook/id1438683531)) ([Android](https://play.google.com/store/apps/details?id=com.awad.saffron))
+- [Single Origin 2](https://singleoriginapp.com/)
+- [Skeel](https://www.skeelapp.com/) ([iOS](https://apps.apple.com/fr/app/skeel-qui-est-le-meilleur/id1292404366)) ([Android](https://play.google.com/store/apps/details?id=com.skeelofficial.reactnativeclient))
+- [Stillwhite: Wedding Dresses](https://www.stillwhite.com/) ([iOS](https://apps.apple.com/us/app/stillwhite-wedding-dresses/id1483180828)) ([Android](https://play.google.com/store/apps/details?id=com.stillwhite.app))
+- [Summer](https://www.summerapp.com/) ([iOS](https://apps.apple.com/app/apple-store/id1512328590?pt=118010433))
+- [Surely Todos](https://www.surelytodo.com/) ([iOS](https://apps.apple.com/us/app/surely/id1586633713)) ([Web](https://www.surelytodo.com/))
+- [Sweepy](https://sweepy.app/)
+- [Tracker Network for Fortnite](https://apps.apple.com/us/app/tracker-network-for-fortnite/id1287696482)
+- [Vrbo](https://www.vrbo.com/mobile/)
+
+## Your app?
+
+If you would like to suggest to add your app to this list, [please open a pull request](https://github.com/react-navigation/website)!
diff --git a/versioned_docs/version-8.x/web-support.md b/versioned_docs/version-8.x/web-support.md
new file mode 100755
index 00000000000..2bb89461c8e
--- /dev/null
+++ b/versioned_docs/version-8.x/web-support.md
@@ -0,0 +1,159 @@
+---
+id: web-support
+title: React Navigation on Web
+sidebar_label: Web support
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+React Navigation has built-in support for the Web platform. This allows you to use the same navigation logic in your React Native app as well as on the web. The navigators require using [React Native for Web](https://github.com/necolas/react-native-web) to work on the web.
+
+## Pre-requisites
+
+While Web support works out of the box, there are some things to configure to ensure a good experience on the web:
+
+1. [**Configure linking**](configuring-links.md)
+
+ Configuring linking allows React Navigation to integrate with the browser's URL bar. This is crucial for web apps to have proper URLs for each screen.
+
+2. [**Use Button or Link components**](link.md)
+
+ You may be familiar with using `navigation.navigate` to navigate between screens. But it's important to avoid using it when supporting the web. Instead, use the `Link` or [`Button`](elements.md#button) components to navigate between screens. This ensures that an anchor tag is rendered which provides the expected behavior on the web.
+
+3. [**Server rendering**](server-rendering.md)
+
+ Currently, React Navigation works best with fully client-side rendered apps. However, minimal server-side rendering support is available. So you can optionally choose to server render your app.
+
+4. **Adapt to web-specific behavior**
+
+ Depending on your app's requirements and design, you may also want to tweak some of the navigators' behavior on the web. For example:
+ - Change `backBehavior` to `fullHistory` for [tabs](bottom-tab-navigator.md#backbehavior) and [drawer](drawer-navigator.md#backbehavior) on the web to always push a new entry to the browser history.
+ - Use sidebars on larger screens instead of [bottom tabs](bottom-tab-navigator.md#tabbarposition) - while not specific to web, responsive design much more important on the web.
+
+:::note
+
+In React Navigation 4, it was necessary to install a separate package called `@react-navigation/web` to use web integration. This package is no longer needed in recent versions of React Navigation. If you have it installed, make sure to uninstall it to avoid conflicts.
+
+:::
+
+## Lazy loading screens
+
+By default, screen components are bundled in the main bundle. This can lead to a large bundle size if you have many screens. It's important to keep the bundle size small on the web for faster loading times.
+
+To reduce the bundle size, you can use [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) with [`React.lazy`](https://react.dev/reference/react/lazy) to lazy load screens:
+
+
+
+
+```js name="Lazy loading screens" snack
+import { Suspense, lazy } from 'react';
+
+const MyStack = createNativeStackNavigator({
+ screenLayout: ({ children }) => (
+ }>{children}
+ ),
+ screens: {
+ Home: {
+ component: lazy(() => import('./HomeScreen')),
+ },
+ Profile: {
+ component: lazy(() => import('./ProfileScreen')),
+ },
+ },
+});
+```
+
+
+
+
+```js name="Lazy loading screens" snack
+import { Suspense, lazy } from 'react';
+
+const HomeScreen = lazy(() => import('./HomeScreen'));
+const ProfileScreen = lazy(() => import('./ProfileScreen'));
+
+function MyStack() {
+ return (
+ (
+ }>{children}
+ )}
+ >
+
+
+
+ );
+}
+```
+
+:::warning
+
+Make sure to use `React.lazy` **outside** the component containing the navigator configuration. Otherwise, it will return a new component on each render, causing the [screen to be unmounted and remounted](troubleshooting.md#screens-are-unmountingremounting-during-navigation) every time the component rerenders.
+
+:::
+
+
+
+
+This will split the screen components into separate chunks (depending on your bundler) which are loaded on-demand when the screen is rendered. This can significantly reduce the initial bundle size.
+
+In addition, you can use the [`screenLayout`](navigator.md#screen-layout) to wrap your screens in a [``](https://react.dev/reference/react/Suspense) boundary. The suspense fallback can be used to show a loading indicator and will be shown while the screen component is being loaded.
+
+## Web-specific behavior
+
+Some of the navigators have different behavior on the web compared to native platforms:
+
+1. [**Native Stack Navigator**](stack-navigator.md)
+
+ Native Stack Navigator uses the platform's primitives to handle animations and gestures on native platforms. However, animations and gestures are not supported on the web.
+
+2. [**Stack Navigator**](stack-navigator.md)
+
+ Stack Navigator uses [`react-native-gesture-handler`](https://docs.swmansion.com/react-native-gesture-handler/) to handle swipe gestures on native platforms. However, gestures are not supported on the web.
+
+ In addition, screen transitions are disabled by default on the web. You can enable them by setting `animationEnabled: true` in the navigator's options.
+
+3. [**Drawer Navigator**](drawer-navigator.md)
+
+ Drawer Navigator uses [`react-native-gesture-handler`](https://docs.swmansion.com/react-native-gesture-handler/) to handle swipe gestures and [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/) for animations on native platforms. However, gestures are not supported on the web, and animations are handled using CSS transitions.
+
+In addition, navigators render hyperlinks on the web when possible, such as in the drawer sidebar, tab bar, stack navigator's back button, etc.
+
+Since `react-native-gesture-handler` and `react-native-reanimated` are not used on the web, avoid importing them in your own code to reduce the bundle size unless you need them for your components. You can use `.native.js` or `.native.ts` extensions for code specific to native platforms.
+
+## Configuring hosting providers
+
+React Navigation is designed for Single Page Applications (SPAs). This usually means that the `index.html` file needs to be served for all routes.
+
+During development, the bundler such as Webpack or Metro automatically handles this. However, when deploying the site, you may need to configure redirects to ensure that the `index.html` file is served for all routes to avoid 404 errors.
+
+Here are instructions for some of the popular hosting providers:
+
+### Netlify
+
+To handle redirects on Netlify, add the following in the `netlify.toml` file at the root of your project:
+
+```toml
+[[redirects]]
+ from = "/*"
+ to = "/index.html"
+ status = 200
+```
+
+### Vercel
+
+To handle redirects on Vercel, add the following in the `vercel.json` file at the root of your project:
+
+```json
+{
+ "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
+}
+```
+
+### GitHub Pages
+
+GitHub Pages doesn't support such redirection configuration for SPAs. There are a couple of ways to work around this:
+
+- Rename your `index.html` to `404.html`. This will serve the `404.html` file for all routes. However, this will cause a 404 status code to be returned for all routes. So it's not ideal for SEO.
+- Write a script that copies the `index.html` file to all routes in the build output. For example, if your app has routes `/`, `/about`, and `/contact`, you can copy the `index.html` file to `about.html` and `contact.html`.
diff --git a/versioned_sidebars/version-8.x-sidebars.json b/versioned_sidebars/version-8.x-sidebars.json
new file mode 100644
index 00000000000..b0bed7c7f5b
--- /dev/null
+++ b/versioned_sidebars/version-8.x-sidebars.json
@@ -0,0 +1,110 @@
+{
+ "docs": {
+ "Fundamentals": [
+ "getting-started",
+ "hello-react-navigation",
+ "navigating",
+ "params",
+ "headers",
+ "header-buttons",
+ "nesting-navigators",
+ "navigation-lifecycle",
+ "next-steps"
+ ],
+ "Guides": [
+ "auth-flow",
+ "handling-safe-area",
+ "customizing-tabbar",
+ "hiding-tabbar-in-screens",
+ "status-bar",
+ "modal",
+ "multiple-drawers",
+ "screen-options-resolution",
+ "custom-android-back-button-handling",
+ "shared-element-transitions",
+ "preventing-going-back",
+ "function-after-focusing-screen",
+ "navigating-without-navigation-prop",
+ "deep-linking",
+ "configuring-links",
+ "web-support",
+ "server-rendering",
+ "screen-tracking",
+ "themes",
+ "state-persistence",
+ "combine-static-with-dynamic",
+ "testing",
+ "typescript",
+ "troubleshooting",
+ "upgrading-from-7.x"
+ ],
+ "Navigators": [
+ "stack-navigator",
+ "native-stack-navigator",
+ "bottom-tab-navigator",
+ "drawer-navigator",
+ "material-top-tab-navigator"
+ ],
+ "Libraries": ["devtools", "elements", "tab-view", "drawer-layout"],
+ "API reference": [
+ "static-configuration",
+ "navigation-container",
+ "server-container",
+ "navigator",
+ "group",
+ "screen",
+ "screen-options",
+ "route-object",
+ "navigation-object",
+ "navigation-context",
+ "navigation-events",
+ "navigation-state",
+ "link",
+ {
+ "type": "category",
+ "collapsible": true,
+ "label": "Hooks",
+ "items": [
+ "use-navigation",
+ "use-route",
+ "use-navigation-state",
+ "use-focus-effect",
+ "use-is-focused",
+ "use-prevent-remove",
+ "use-route-path",
+ "use-link-to",
+ "use-link-props",
+ "use-link-builder",
+ "use-scroll-to-top",
+ "use-theme"
+ ]
+ },
+ {
+ "type": "category",
+ "collapsible": true,
+ "label": "Actions",
+ "items": [
+ "navigation-actions",
+ "stack-actions",
+ "drawer-actions",
+ "tab-actions"
+ ]
+ }
+ ],
+ "Build your own Navigator": ["custom-routers", "custom-navigators"],
+ "Ecosystem": [
+ "community-solutions",
+ "community-navigators",
+ "community-libraries",
+ "more-resources"
+ ],
+ "Meta": [
+ "migration-guides",
+ "glossary-of-terms",
+ "pitch",
+ "limitations",
+ "used-by",
+ "contributing"
+ ]
+ }
+}
diff --git a/versions.json b/versions.json
index 9aca05ea139..efdafab2cad 100644
--- a/versions.json
+++ b/versions.json
@@ -1 +1 @@
-["7.x", "6.x", "5.x", "4.x", "3.x", "2.x", "1.x"]
+["8.x", "7.x", "6.x", "5.x", "4.x", "3.x", "2.x", "1.x"]