# Technical Documentation: wix/react-native-navigation

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/wix/react-native-navigation)

### Overview (`README.md`)

[](https://vshymanskyy.github.io/StandWithUkraine)

<h1 align="center">
  <img src=".logo.png"/><br/>
  React Native Navigation
</h1>

<p align="center">
  <a href="https://www.npmjs.com/package/react-native-navigation"><img src="https://img.shields.io/npm/dw/react-native-navigation.svg?style=flat-square" alt="NPM downloads"></a>
  <a href="https://www.npmjs.com/package/react-native-navigation"><img src="https://img.shields.io/npm/v/react-native-navigation/latest.svg?style=flat-square" alt="NPM latest version"></a>
  <a href="https://www.npmjs.com/package/react-native-navigation"><img src="https://img.shields.io/npm/v/react-native-navigation/snapshot.svg?style=flat-square" alt="NPM snapshot version"></a>
  <a href="https://github.com/wix/react-native-navigation/actions/workflows/release.yml"><img src="https://img.shields.io/badge/release-GitHub%20Actions-2088FF?style=flat-square&logo=githubactions&logoColor=white" alt="GitHub Release workflow"></a>

</p>
<p align="center">
  <a href="https://twitter.com/reactnativenav"><img src="https://img.shields.io/twitter/follow/reactnativenav.svg?style=flat-square&colorA=1da1f2&colorB=&label=Follow%20us%20on%20Twitter" alt="Follow on Twitter"></a>
  <a href="https://discord.gg/DhkZjq2"><img src="https://img.shields.io/discord/242515947020222464.svg?color=%237289da&label=Chat%20on%20Discrd&style=flat-square" alt="Chat on Discord"></a>
  <a href="https://stackoverflow.com/questions/tagged/wix-react-native-navigation"><img src="https://img.shields.io/stackexchange/stackoverflow/t/wix-react-native-navigation.svg?style=flat-square" alt="StackExchange"></a>
</p>

React Native Navigation provides 100% native platform navigation on both iOS and Android for React Native apps. The JavaScript API is simple and cross-platform - just install it in your app and give your users the native feel they deserve. Ready to get started? Check out the [docs](https://wix.github.io/react-native-navigation/).

# Quick Links

- [Documentation](https://wix.github.io/react-native-navigation/)
- [Changelog](https://github.com/wix/react-native-navigation/blob/master/CHANGELOG.md)
- [Stack Overflow](http://stackoverflow.com/questions/tagged/wix-react-native-navigation)
- [Chat with us](https://discord.gg/DhkZjq2)
- [Contributing](https://wix.github.io/react-native-navigation/docs/meta-contributing)

# Requirements

Apps using React Native Navigation may target iOS 11 and Android 5.0 (API 21). You may use Windows, macOS or Linux as your development operating system.

# Installation

As `react-native-navigation` is a native navigation library - integrating it into your app will require editing native files. Follow the installation guides in the [documentation](https://wix.github.io/react-native-navigation/).

## Releases

Repository administrators: see the [release runbook](docs/RELEASING.md) for manual releases,
npm trusted publishing setup, and recovery.

---

### Overview (`playground/README.md`)

# Navigation Playground

A local example project using `react-native-navigation`.
The target app for all e2e tests.

---

### Overview (`test-app/README.md`)

This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli).

# Getting Started

> **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding.

## Step 1: Start Metro

First, you will need to run **Metro**, the JavaScript build tool for React Native.

To start the Metro dev server, run the following command from the root of your React Native project:

```sh
# Using npm
npm start

# OR using Yarn
yarn start
```

## Step 2: Build and run your app

With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app:

### Android

```sh
# Using npm
npm run android

# OR using Yarn
yarn android
```

### iOS

For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps).

The first time you create a new project, run the Ruby bundler to install CocoaPods itself:

```sh
bundle install
```

Then, and every time you update your native dependencies, run:

```sh
bundle exec pod install
```

For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html).

```sh
# Using npm
npm run ios

# OR using Yarn
yarn ios
```

If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device.

This is one way to run your app — you can also build it directly from Android Studio or Xcode.

## Step 3: Modify your app

Now that you have successfully run the app, let's make changes!

Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh).

When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload:

- **Android**: Press the <kbd>R</kbd> key twice or select **"Reload"** from the **Dev Menu**, accessed via <kbd>Ctrl</kbd> + <kbd>M</kbd> (Windows/Linux) or <kbd>Cmd ⌘</kbd> + <kbd>M</kbd> (macOS).
- **iOS**: Press <kbd>R</kbd> in iOS Simulator.

## Congratulations! :tada:

You've successfully run and modified your React Native App. :partying_face:

### Now what?

- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps).
- If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started).

# Troubleshooting

If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page.

# Learn More

To learn more about React Native, take a look at the following resources:

- [React Native Website](https://reactnative.dev) - learn more about React Native.
- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment.
- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**.
- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts.
- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native.

---

### RELEASING (`docs/RELEASING.md`)

# Releasing React Native Navigation

The [Release workflow](https://github.com/wix/react-native-navigation/actions/workflows/release.yml)
is the only supported npm publisher. Repository admins start it manually on `master`.
Both regular releases and snapshots use npm trusted publishing with GitHub OIDC.
Buildkite runs native tests; it no longer versions or publishes packages. Its expired npm
credentials must not be renewed as a fallback.

## One-time configuration

A repository admin and an npm package administrator must complete these steps before
enabling publication. Creating or merging the workflow does not configure npm trust.

1. Create the GitHub environment `npm-release`. Under deployment branches and tags,
   select only the **branch** `master`. Protect `master` and review changes to release
   workflows and helpers. Required environment reviewers are optional; enabling them
   introduces approvals for the record, publish, and finalize jobs.
2. In the npm settings for `react-native-navigation`, add a GitHub Actions trusted publisher:

   | Field             | Value                     |
   | ----------------- | ------------------------- |
   | Organization      | `wix`                     |
   | Repository        | `react-native-navigation` |
   | Workflow filename | `release.yml`             |
   | Environment       | `npm-release`             |
   | Allowed action    | Direct `npm publish`      |

   Explicitly allow direct publication: a stage-only configuration cannot complete this
   workflow. Standalone `npm dist-tag` permission is not needed. See
   [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/).

3. Enable GitHub Actions for this repository. Check Wix's Actions policy permits the pinned checkout, setup-node, upload-artifact,
   and download-artifact actions. Allow workflow-created pull requests. Ensure existing
   repository rules permit version branches and release tags without a bypass.
4. Check the GitHub commit status `buildkite/react-native-navigation` represents all
   Android/iOS lanes in `.buildkite/pipeline.sh`. It must finish successfully on the
   exact `master` commit selected by the release run. The status creator must match
   the Buildkite app ID/login pinned in `scripts/release/rnn.cjs`. A failed, absent, or pending status
   blocks real publication, including snapshots. A dry run reports it without publishing.
5. Verify a dry run and inspect its artifact. Then set the repository Actions variable
   `RELEASE_PUBLISH_ENABLED` to `true`. Without it, publish and resume fail closed.
6. Run an intentional snapshot publication and verify the npm version, integrity,
   provenance, and `snapshot` dist-tag. Confirm that `latest` did not change.
7. Remove obsolete release-only npm secret injection and restrict traditional token
   publishing in npm's package settings. Do not renew expired tokens. A shared credential
   must not be revoked until its other consumers have been identified.

No npm write token is needed in GitHub. `GITHUB_TOKEN` performs repository bookkeeping;
only the publish job has `id-token: write`. Publishing runs on a GitHub-hosted Ubuntu
runner. The workflow uses Node 24.22.1, including npm 11.19.1; update this tested pair
together. Older npm releases can execute `prepare` during `npm pack --ignore-scripts`.

## Start a release

Open **Actions → Release → Run workflow**, select `master`, and supply:

| Input                          | Meaning                                                                        |
| ------------------------------ | ------------------------------------------------------------------------------ |
| `operation`                    | `dry-run` (default), `publish`, or `resume`                                    |
| `kind`                         | `release` or `snapshot`                                                        |
| `version`                      | Exact semver for releases; empty for snapshots                                 |
| `npm_tag`                      | `latest` for stable versions, `next` for prereleases, `snapshot` for snapshots |
| `documentation_version`        | Optional numeric `x.y.z` documentation snapshot                                |
| `remove_documentation_version` | Optional existing version to remove while generating its replacement           |
| `source_run_id`                | Original publishing run ID, for resume only                                    |

Examples:

- Stable: `kind=release`, `version=8.9.1`, `npm_tag=latest`.
- Prerelease: `kind=release`, `version=8.9.0-rc.1`, `npm_tag=next`.
- Snapshot: `kind=snapshot`, leave version empty, `npm_tag=snapshot`.

The selected version must be newer than npm `latest`. Build metadata such as `+build.1`
is intentionally unsupported. Snapshots use `<base>-snapshot.gha.<run_id>`, with the
base derived from the greater of the source package version and npm `latest`. The
run attempt is not part of the version. Snapshots do not create tags, GitHub releases,
version PRs, or documentation changes.

Users with write access may see GitHub's Run workflow button, but both the original
actor and the user rerunning/resuming the workflow must have repository-admin permission.
The workflow rechecks authorization before every job that changes external state.

## What the workflow does

1. Records the exact source SHA, chosen version/channel, and native CI result.
2. Installs the locked Yarn dependencies, changes release metadata, builds JS and
   declarations with Bob, and runs JavaScript and release-helper tests on Linux.
3. Optionally installs the locked website dependencies, generates the requested docs
   version, and builds the site. Removal requires an existing numeric version; replacing
   an existing version requires explicitly selecting that same version for removal.
4. Creates a local release commit containing only the version and optional versioned
   docs, then packs the already built package. Package contents and exported paths are
   checked. Android/iOS sources ship in the package; this job does not compile native apps.
5. Uploads a versioned manifest, the tarball, release notes, and a Git bundle as
   `release-<run_id>-<run_attempt>`. A dry run ends here with no external release mutations.
6. For real releases, persists `ci/update-version-<version>`, then publishes the verified
   tarball using OIDC. The publisher does not install project dependencies or rebuild it.
7. Verifies npm integrity, tags the source commit on `master` with the bare version (for example
   `8.9.1`), creates a GitHub release, and opens a version/documentation PR with the
   `release` label. An existing PR template is included with its checkboxes left for review.

Release notes include merged PRs from the preceding reachable stable tag through the
source commit. They preserve feature/enhancement/fix categories, platform groups, and
`skip-changelog` exclusions. No second `gren` invocation or timed retry is involved.

Review and merge the version PR after publication. Documentation deploys through the
existing documentation workflow after that merge. Events created with `GITHUB_TOKEN` do not
start Actions workflows, so Release checks will not run on the version PR; Buildkite still
builds it through its webhook. Inspect the PR's checks before merging. The release workflow
does not invoke engine notification.

## Resume a partial release

Use **Re-run failed jobs** when the original run still has its preparation outputs, or
dispatch `operation=resume` with `source_run_id` set to the original **publish** run.
Other release inputs are ignored in resume mode. Do not enter a different version to
recover from a GitHub or network error.

Recovery validates the upstream workflow identity, source SHA, native CI, artifact
integrity, release commit, and package metadata. It downloads the saved artifacts and
does not rebuild against the current branch. If the version is still absent from npm and
`master` has advanced, re-run the original publishing run instead of dispatching a new
resume run: npm provenance must identify the source commit that built the package. A new
resume dispatch may finish GitHub bookkeeping for an already published matching tarball.

| State                                             | Result                                                                     |
| ------------------------------------------------- | -------------------------------------------------------------------------- |
| Version absent from npm                           | Publish the original tarball, provided its channel would not move backward |
| Same version and same integrity already published | Skip publication and finish GitHub steps                                   |
| Same version with different integrity             | Stop; investigate the conflicting publication                              |
| Registry failure or lost response                 | Fail without choosing another version; resume when healthy                 |
| Existing branch/tag/PR matches                    | Reuse it                                                                   |
| Existing branch/tag/PR conflicts                  | Stop; never force-push or move a tag                                       |
| Dry-run artifact selected                         | Reject; start a fresh publish run                                          |
| Artifact expired/deleted                          | Stop automatic recovery                                                    |

Artifacts request 90-day retention, subject to organization limits. Retain artifacts until
the version PR is merged and the release is verified. After artifact loss, an admin must
investigate the existing registry version and persisted release branch manually; do not
reconstruct and publish different bytes under the same version or automatically fall back
to the old pipeline. npm and GitHub do not provide a cross-service atomic transaction.

The concurrency group serializes all release attempts. GitHub may replace a pending run
when another dispatch is queued; it does not cancel the running publisher. Check each run's
state rather than assuming every click is queued indefinitely.

## Validate changes to the release tooling

With Node 24.22.1 and npm 11.19.1:

```sh
node --test scripts/release/*.test.cjs
node .yarn/releases/yarn-4.12.0.cjs install --immutable
node .yarn/releases/yarn-4.12.0.cjs prepare
node .yarn/releases/yarn-4.12.0.cjs test-js
RELEASE_DIR=/tmp/rnn-package node scripts/release/index.cjs pack-check
```

`pack-check` only prepares and inspects a local tarball. The read-only Release checks
workflow runs the tests and clean Linux package check on PRs. A real OIDC publication
still needs the default-branch workflow and the npm/GitHub configuration above.

## Removed release paths and retained consumers

The Buildkite release form, publishing job, legacy `scripts/release.js`, `gren` config,
and root/playground `github-release-notes` dependencies have been removed. Automatic
Buildkite snapshots are replaced by manual snapshots. Native Buildkite testing remains.

Outside the repository, remove obsolete release schedules/hooks and release-only
`NPM_TOKEN`/`NPM_EMAIL` injection. Inspect any old Jenkins configuration referenced by
historical setup; the old README badge alone does not prove an active publisher exists.

Keep the tracked registry-only `.npmrc`, documentation deployment's `GH_PAGES_DEPLOY`,
and any Git credential still used by `scripts/test-snapshot.js` to record reference images.
Do not delete shared secrets merely because the old publisher also used them.

For the next repository, use [the migration checklist](release-migration-checklist.md).

---

### Release Migration Checklist (`docs/release-migration-checklist.md`)

# Migrating another repository to trusted publishing

RNN establishes a release contract: admin dispatch, explicit versions, immutable build
artifacts, OIDC publication, and recovery of the same package bytes. Copy the contract
before extracting shared code. Repository-specific build and package policy lives in
`scripts/release/rnn.cjs`; the current workflow and manifest validator intentionally accept
only RNN. Another repository must implement and test its own adapter and authorization.

## Inventory before changing a publisher

- Read the target repository's instructions and release tests.
- List every publishable package, its source directory, version authority, dist-tags,
  Git tag convention, and dependency relationship to the other packages.
- Trace release-trigger inputs, lifecycle hooks, generated artifacts, documentation,
  release notes, PRs, and any native packaging commands.
- Identify native CI evidence by exact commit. Distinguish the tools needed to produce
  the npm package from tools needed only for testing.
- Inventory CI schedules, webhooks, release credentials, and other consumers of shared
  credentials. A release script deletion alone does not remove an external trigger.

## Implement the repository adapter

- Keep a stable repository-local `release.yml` entry point and protected environment.
- Configure allowed branches, admin authorization, packages, runners, build commands,
  expected tarball contents, version/dependency rewrites, and tag naming.
- Resolve the complete package/version plan before the first publish. Use an ordered
  package list and store each package's integrity in the manifest.
- Build without npm publishing credentials. Native preparation can use separate runner
  jobs; the OIDC publisher must run on a supported GitHub-hosted runner.
- Preserve artifacts and verify their original workflow/source identity during recovery.
- Publish each package only if absent. If already present, require matching integrity.
  Never bump all versions after a partial publish. Multi-package publication is not atomic.
- Register npm trust separately for every package. If introducing reusable workflows,
  check npm's caller-workflow identity rules and grant the required OIDC permissions at
  the caller/callee boundaries. Pin shared implementations to reviewed commit SHAs.

## Known differences from RNN

| Repository              | Migration requirement                                                                                                                                           |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| react-native-navigation | One package, Bob JS/types build, native sources, bare version Git tags                                                                                          |
| react-native-ui-lib     | Separate `uilib-native` and `react-native-ui-lib` versions; native package first when selected; rewrite workspace dependencies; preserve package-qualified tags |
| Detox                   | Discover and validate publishable workspaces; preserve synchronized versions; trace Android and iOS native artifact packaging before choosing runners           |

UI-lib's starting points are `scripts/release/release.js`, `releaseUtils.js`, and the
existing release-script tests. Its dependency rewrite must use the planned or verified
published native version, including when only one package needs publication.

Detox's starting points are `scripts/ci.release.js`, `scripts/utils/publishNewVersion.js`,
`scripts/ci.android-release.js`, `scripts/ci.ios-release.sh`, and the Buildkite release
pipelines. Android packaging invokes the SDK and Gradle. Resolve the current iOS packaging
entry point before replacing its artifact download flow. Do not assume RNN's Linux-only
package preparation applies to Detox.

## Clean up and verify

- Delete obsolete publishing jobs, forms, entry points, credential-writing helpers,
  retry-by-version-increment code, dead dependencies, and stale instructions.
- Preserve native tests, useful history, documentation deployment, and shared credentials
  with remaining consumers.
- Test dry-run non-mutation, unauthorized dispatch/rerun, version/channel validation,
  source CI gating, package completeness, and lost-response/partial-publication recovery.
- Verify clean runner builds, then a deliberate prerelease/snapshot using real OIDC.
- Document one-time configuration, remaining infrastructure cleanup, and artifact-loss
  recovery. Expired token-based publishers are not an automatic fallback.

Extract the common publisher, authorization, and artifact-state helpers only after a
second adopter confirms their interface. Build commands, package graphs, documentation,
and version conventions should remain repository-specific.

---

### Api Api Component (`website/docs/api/api-component.mdx`)

---
id: component
title: Component
sidebar_label: Component
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## `registerComponent`
Every screen component in your app must be registered with a unique name. The component itself is a traditional React component extending `React.Component` or `React.PureComponent`. It can also be a HOC to provide context (or a Redux store) or a functional component. Similar to React Native's `AppRegistry.registerComponent`.

#### Parameters
| Name   | Required | Type                | Description                                                                                                            |
| ------ | -------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| componentName | Yes      | string | Unique component name - not to be confused with **componentId** |
| componentProvider | Yes      | Function | Anonymous function that returns the React component to register, **OR** the component wrapped with Providers|
| concreteComponentProvider | No      | Function | Anonymous function that returns the concrete React component. If your component is wrapped with Providers, this must be an instance of the concrete component.|

#### Examples
##### Registering a component
```js
Navigation.registerComponent(`navigation.playground.WelcomeScreen`, () => WelcomeScreen);
```

##### Registering a component wrapped with Providers
```js
import { Provider } from 'react-redux';
const store = createStore();

Navigation.registerComponent(`navigation.playground.MyScreen`, () => (props) =>
  <Provider store={store}>
    <MyScreen {...props} />
  </Provider>,
  () => MyScreen)
);
```

## `setLazyComponentRegistrator`
Pass a function that will allow you to register a component lazily. When encountering an unknown component name, this function will be called, giving you a chance to register the component before an error is thrown.

#### Parameters
| Name   | Required | Type                | Description                                                                                                            |
| ------ | -------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| lazyRegistratorFn | Yes      | (lazyComponentRequest: string | number) => void | A function that takes a componentName, will be called when encountering an unknown componentName |

#### Example
```js
Navigation.setLazyComponentRegistrator((componentName) => {
  if (componentName === 'navigation.playground.LazyScreen') {
    Navigation.registerComponent(Screens.LazilyRegisteredScreen, () => LazyScreen);
  }
});
```

## `updateProps`
Update props of a component registered with [registerComponent](#registercomponent). Updating props triggers the component lifecycle methods related to [updating](https://reactjs.org/docs/react-component.html#updating).

#### Parameters
| Name        | Required | Type     | Description                                                                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| componentId | Yes      | string   | Unique component id                                               |
| options     | Yes      | object   | Props object to pass to the component                             |
| callback    | No       | Function | Function that will be executed once inner `setState` is completed |

#### Example
```js
Navigation.updateProps('MY_COMPONENT', {
  // props to pass to the component
};
```

:::important
`updateProps` is called with a componentId. This is the same unique id components have in props. Don't confuse it with the `componentName` we use when registering components with [Navigation.registerComponent](#registerComponent).
:::

---

### Api Api Events (`website/docs/api/api-events.mdx`)

---
id: events
title: Events
sidebar_label: Events
---

## onAppLaunched

Called once the app is launched. Used to set the initial layout of the Application - after that the app is ready for user interaction.

```js
const appLaunchedListener = Navigation.events().registerAppLaunchedListener(() => {});
```

RNN automatically unsubscribes components when they unmount, therefore unsubscribing isn't actually mandatory if you subscribed in `componentDidMount`.

But you can use the following method to unsubscribe manually:

```js
appLaunchedListener.remove();
```

## componentWillAppear

Called each time before this component appears on the screen (notifies that the component view is about to be added to the view hierarchy).

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  componentWillAppear() {}
}
```

## componentDidAppear

Called each time this component appears on the screen (attached to the view hierarchy).

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  componentDidAppear() {}
}
```

This event can be observed globally as well:

```js
// Subscribe
const screenEventListener = Navigation.events().registerComponentDidAppearListener(({ componentId, componentName, passProps }) => {

});
...
// Unsubscribe
screenEventListener.remove();
```

|     Parameter     | Description                                                                               |
| :---------------: | :---------------------------------------------------------------------------------------- |
|  **componentId**  | Id of the appearing component                                                             |
| **componentName** | Registered name used when registering the component with `Navigation.registerComponent()` |
|   **passProps**   | props passed to the component                                                             |

## componentDidDisappear

Called each time this component disappears from the screen (detached from the view hierarchy).

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  componentDidDisappear() {}
}
```

This event can be observed globally as well:

```js
// Subscribe
const screenEventListener = Navigation.events().registerComponentDidDisappearListener(({ componentId, componentName }) => {

});
...
// Unsubscribe
screenEventListener.remove();
```

|     Parameter     | Description                                                                               |
| :---------------: | :---------------------------------------------------------------------------------------- |
|  **componentId**  | Id of the disappearing component                                                          |
| **componentName** | Registered name used when registering the component with `Navigation.registerComponent()` |

## registerCommandListener

The `commandListener` is called whenever a _Navigation command_ (i.e push, pop, showModal etc) is invoked.

```js
// Subscribe
const commandListener = Navigation.events().registerCommandListener((name, params) => {

});
...
// Unsubscribe
commandListener.remove();
```

| Parameter  | Description                                                                                                                                                                                                                                  |
| :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|  **name**  | The name of the command that was invoked. For example `push`                                                                                                                                                                                 |
| **params** | `commandId`: Each command is assigned a unique Id<br />`componentId`: Optional, the componentId passed to the command<br />`layout`: Optional, if the command invoked created a screen. Slim representation of the component and its options |

## registerCommandCompletedListener

Invoked when a command finishes executing in native. If the command contains animations, for example pushed screen animation, the listener is invoked after the animation ends.

```js
// Subscribe
const commandCompletedListener = Navigation.events().registerCommandCompletedListener(({ commandId, completionTime, params }) => {

});
...
// Unsubscribe
commandCompletedListener.remove();
```

|     Parameter      | Description                                                        |
| :----------------: | :----------------------------------------------------------------- |
|   **commandId**    | Id of the completed command                                        |
| **completionTime** | Timestamp when the command, and consecutive animations, completed. |

## registerModalDismissedListener

Invoked when a modal is dismissed.

```js
// Subscribe
const modalDismissedListener = Navigation.events().registerModalDismissedListener(({ componentId, modalsDismissed }) => {

});
...
// Unsubscribe
modalDismissedListener.remove();
```

|      Parameter      | Description                          |
| :-----------------: | :----------------------------------- |
|   **componentId**   | Id of the modal                      |
| **modalsDismissed** | Number of modals that were dismissed |

## registerModalAttemptedToDismissListener(iOS 13+ only)

Invoked only on iOS pageSheet modal when `swipeToDismiss` flag is set to true and modal was swiped down to dismiss.

```js
// Subscribe
const modalAttemptedToDismissListener = Navigation.events().registerModalAttemptedToDismissListener(({ componentId }) => {

});
...
// Unsubscribe
modalAttemptedToDismissListener.remove();
```

|    Parameter    | Description                                     |
| :-------------: | :---------------------------------------------- |
| **componentId** | Id of the modal a user is attempting to dismiss |

## registerScreenPoppedListener

Invoked when the screen is popped.

```js
// Subscribe
const screenPoppedListener = Navigation.events().registerScreenPoppedListener(({ componentId }) => {

});
...
// Unsubscribe
screenPoppedListener.remove();
```

|    Parameter    | Description                       |
| :-------------: | :-------------------------------- |
| **componentId** | Id of the screen which was popped |

## registerBottomTabPressedListener

Invoked when a bottom tab is pressed by the user, including when [`selectTabOnPress`](options-bottomTab.mdx#selecttabonpress) is `false` (the selected tab does not change).

```js
// Subscribe
const bottomTabEventListener = Navigation.events().registerBottomTabPressedListener(({ tabIndex }) => {

});
...
// Unsubscribe
bottomTabEventListener.remove();
```

| Parameter   | Description                         |
| :---------: | :---------------------------------- |
| **tabIndex** | Index of the tab that was pressed |

Works with [custom bottom tab items](../docs/docs-customBottomTabs.mdx) on iOS and Android.

## registerBottomTabSelectedListener

Invoked when BottomTab is selected by a user.

```js
// Subscribe
const bottomTabEventListener = Navigation.events().registerBottomTabSelectedListener(({ selectedTabIndex, unselectedTabIndex }) => {

});
...
// Unsubscribe
bottomTabEventListener.remove();
```

|       Parameter        | Description                          |
| :--------------------: | :----------------------------------- |
|  **selectedTabIndex**  | Index of the newly selected tab      |
| **unselectedTabIndex** | Index of the previously selected tab |

Works with [custom bottom tab items](../docs/docs-customBottomTabs.mdx) on iOS and Android.

## registerBottomTabLongPressedListener

Invoked when BottomTab is long pressed by a user. **iOS only.** Not emitted for [custom bottom tab items](../docs/docs-customBottomTabs.mdx) — long press is handled on the native tab bar, which is hidden when every tab uses `bottomTab.component`.

```js
// Subscribe
const bottomTabEventListener = Navigation.events().registerBottomTabLongPressedListener(({ selectedTabIndex }) => {

});
...
// Unsubscribe
bottomTabEventListener.remove();
```

## navigationButtonPressed event

This event is emitted whenever a TopBar button is pressed by a user.

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Unregistering listeners bound to components isn't mandatory since RNN handles the unregistration for you
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  navigationButtonPressed({ buttonId }) {}
}
```

This event can be observed globally as well:

```js
// Subscribe
const navigationButtonEventListener = Navigation.events().registerNavigationButtonPressedListener(({ buttonId }) => {

});
...
// Unsubscribe
navigationButtonEventListener.remove();
```

|  Parameter   | Description                            |
| :----------: | :------------------------------------- |
| **buttonId** | `buttonId`: `id` of the pressed button |

## searchBarUpdated (iOS 11+ only)

Called whenever the SearchBar of NavigationBar is updated.

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  searchBarUpdated({ text, isFocused }) {}
}
```

## searchBarCancelPressed (iOS 11+ only)

Called when the cancel button of the SearchBar from NavigationBar is pressed.

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  searchBarCancelPressed() {}
}
```

## previewCompleted (iOS 11.4+ only)

Called when preview peek is completed.

```js
class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  previewCompleted({ previewComponentId }) {}
}
```

---

### Api Api Modal (`website/docs/api/api-modal.mdx`)

---
id: modal
title: Modal
sidebar_label: Modal
---
## `showModal()`
Show a screen as a modal.

#### Parameters
| Name   | Required | Type                | Description                                                                                                            |
| ------ | -------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| layout | Yes      | [Layout](layout-layout.mdx) | Any type of layout. [BottomTabs](layout-BottomTabs.mdx), [Stack](layout-stack.mdx), [SideMenu](layout-sideMenu.mdx), [Component](layout-component.mdx) |

```js
Navigation.showModal({
  stack: {
    children: [{
      component: {
        name: 'example.ModalScreen',
        passProps: {
          text: 'stack with one child'
        },
        options: {
          topBar: {
            title: {
              text: 'Modal'
            }
          }
        }
      }
    }]
  }
});
```

## `dismissModal()`
Dismiss the current modal.

#### Parameters
| Name         | Required | Type    | Description                                                |
| ------------ | -------- | ------- | ---------------------------------------------------------- |
| componentId  | Yes      | string  | Any component id presented in the modal                    |
| mergeOptions | No       | Options | Options to be merged before dismissing the Modal. |

```js
Navigation.dismissModal(this.props.componentId);
```

## `dismissAllModals()`
Dismiss all current modals at the same time.

#### Parameters
| Name         | Required | Type    | Description                                                |
| ------------ | -------- | ------- | ---------------------------------------------------------- |
| mergeOptions | No       | Options | Options to be merged before dismissing all modals. |

```js
Navigation.dismissAllModals();
```

---

### Api Api Options (`website/docs/api/api-options.mdx`)

---
id: options-api
title: Options Commands
sidebar_label: Options commands
---

## `setDefaultOptions`

Set default options for all screens. Useful for declaring a consistent style across the app.

#### Parameters

| Name    | Type                        | Required | Description  |
| ------- | --------------------------- | -------- | ------------ |
| options | [Options](options-root.mdx) | Yes      | Options root |

#### Example

```js
Navigation.setDefaultOptions({
  bottomTab: {
    textColor: 'black',
    selectedTextColor: 'blue',
  },
});
```

## `mergeOptions`

Change navigation options of a component or layout.

#### Parameters

| Name        | Type                        | Required | Description                |
| ----------- | --------------------------- | -------- | -------------------------- |
| componentId | string                      | Yes      | The component or layout id |
| options     | [Options](options-root.mdx) | Yes      | Options root               |

#### Example

```js
Navigation.mergeOptions('componentId', {
  bottomTabs: {
    visible: false,
  },
});
```

---

### Api Api Overlay (`website/docs/api/api-overlay.mdx`)

---
id: overlay
title: Overlay
sidebar_label: Overlay
---

## `showOverlay()`
Shows a component as an overlay.

| Name   | Required | Type                | Description                                                                                                                                                                                                         |
| ------ | -------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| layout | Yes      | [Layout](layout-layout.mdx) | Any type of layout. Typically, Component layout is used in Overlays but it's possible to load any other layout ([BottomTabs](layout-BottomTabs.mdx), [Stack](layout-stack.mdx), [SideMenu](layout-sideMenu.mdx), [Component](layout-component.mdx)) |

```js
Navigation.showOverlay({
  component: {
    name: 'example.Overlay',
    options: {
      layout: {
            componentBackgroundColor: 'transparent',
          },
      overlay: {
        interceptTouchOutside: true
      }
    }
  }
});
```

## `dismissOverlay()`
Dismisses an overlay matching the given overlay componentId.

#### Parameters
| Name        | Required | Type   | Description                           |
| ----------- | -------- | ------ | ------------------------------------- |
| componentId | Yes      | string | The component id presented in Overlay |

```js
Navigation.dismissOverlay(this.props.componentId);
```

## `dismissAllOverlays()`
Dismisses all overlays.

```js
Navigation.dismissAllOverlays();
```

---

### Api Api Root (`website/docs/api/api-root.mdx`)

---
id: root
title: Root
sidebar_label: Root
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## `setRoot()`
Used to set the UI of the application. Read more about the root hierarchy level in the [docs section](../docs/root).

#### Parameters
| Name   | Required | Type                | Description                                                                                                            |
| ------ | -------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| layout | Yes      | [Layout](layout-layout.mdx) | Any type of layout. [BottomTabs](layout-BottomTabs.mdx), [Stack](layout-stack.mdx), [SideMenu](layout-sideMenu.mdx), [Component](layout-component.mdx) |

#### Example

<Tabs
  defaultValue='stack'
  values={[
    { label: 'With Stack layout', value: 'stack' },
    { label: 'With BottomTabs layout', value: 'bottomTabs' }
  ]
}>

<TabItem value='stack'>

```js
Navigation.setRoot({
  root: {
    stack: {
      children: [{
        component: {
          name: 'example.FirstTabScreen',
          passProps: {
            text: 'This is tab 1'
          }
        }
      }],
      options: {
        bottomTab: {
          text: 'Tab 1',
          icon: require('../images/one.png'),
          testID: 'FIRST_TAB_BAR_BUTTON'
        }
      }
    }
  }
});
```

</TabItem>

<TabItem value='bottomTabs'>

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      children: [{
        stack: {
          children: [{
            component: {
              name: 'example.FirstTabScreen',
              passProps: {
                text: 'This is tab 1'
              }
            }
          }],
          options: {
            bottomTab: {
              text: 'Tab 1',
              icon: require('../images/one.png'),
              testID: 'FIRST_TAB_BAR_BUTTON'
            }
          }
        }
      },
      {
        component: {
          name: 'navigation.playground.TextScreen',
          passProps: {
            text: 'This is tab 2'
          },
          options: {
            bottomTab: {
              text: 'Tab 2',
              icon: require('../images/two.png'),
              testID: 'SECOND_TAB_BAR_BUTTON'
            }
          }
        }
      }]
    }
  }
});
```

</TabItem>

</Tabs>

---

### Api Api SideMenu (`website/docs/api/api-sideMenu.mdx`)

---
id: sideMenu-api
title: Side Menu
sidebar_label: Side Menu
---

This layout allows to implement sidemenus, which can be opened by swiping from one side towards the other side.

```js
{
  left: {
    component: {}
  },
  center: {
    stack: {
      options: {},
      children: [{
        component: {}
      }]
    }
  },
  right: {
    component: {}
  }
}
```

## `center: Layout`
Center component, contains the main application.
## `left?: Layout`
Contain the left component layout.
## `right?: Layout`
Contain the right component layout.

---

### Api Api Stack (`website/docs/api/api-stack.mdx`)

---
id: stack
title: Stack
sidebar_label: Stack
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## `push()`
Push a screen into the stack and update the display according to the screen options.
#### Parameters
| Name        | Required | Type   | Description                                                                                                                                                                                                      |
| ----------- | -------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| componentId | Yes      | string | The componentId of a screen pushed into the stack, or the id of the stack.                                                                                                                                            |
| layout      | No       | Layout | The layout being pushed into the stack. Any type of layout (except stack) can be pushed into stacks. Typically, Component layout is pushed into stacks but it's possible to push SideMenu or BottomTabs as well. |

#### Example

<Tabs
  defaultValue='component'
  values={[
    { label: 'Component', value: 'component', },
    { label: 'Update options on push', value: 'push', },
    { label: 'Push other layouts', value: 'otherLayout', },
  ]
}>

<TabItem value='component'>
The most common use case - push a single React component.

```js
Navigation.push(this.props.componentId, {
  component: {
    name: 'example.PushedScreen'
  }
});
```

</TabItem>

<TabItem value='push'>
Options are applied when the screen becomes visible.

```js
Navigation.push(this.props.componentId, {
  component: {
    name: 'example.PushedScreen',
    options: {
      topBar: {
        title: {
          text: 'Pushed screen title'
        }
      }
    }
  }
});
```

</TabItem>

<TabItem value='otherLayout'>
Any layout type can be pushed. In this example we push a SideMenu layout.

```js
Navigation.push(this.props.componentId, {
  sideMenu: {
    left: {
      component: {
        name: 'drawerScreen'
      }
    },
    center: {
      component: {
        name: 'centerScreen'
      }
    }
  }
});
```

</TabItem>

</Tabs>

## `pop()`
Pop the top screen from the stack.
#### Parameters
| Name         | Required | Type                                | Description                                                           |
| ------------ | -------- | ----------------------------------- | --------------------------------------------------------------------- |
| componentId  | Yes      | string                              | The componentId of a screen pushed into the stack, or the stack id. |
| mergeOptions | No       | [Options](options-root.mdx) | Options to be merged before popping the screen (optional).              |

```js
Navigation.pop(this.props.componentId);
```

## `popToRoot()`
Pop all screens pushed into the stack.

#### Parameters
| Name         | Required | Type    | Description                                                           |
| ------------ | -------- | ------- | --------------------------------------------------------------------- |
| componentId  | Yes      | string  | The componentId of a screen pushed into the stack, or the stack id. |
| mergeOptions | No       | [Options](options-root.mdx) | Options to be merged before popping the screen (optional).              |

```js
Navigation.popToRoot(this.props.componentId);
```

## `popTo()`
Pop the stack to a given component.

#### Parameters
| Name         | Required | Type                  | Description                                              |
| ------------ | -------- | --------------------- | -------------------------------------------------------- |
| componentId  | Yes      | string                | The destination componentId                              |
| mergeOptions | No       | [Options](options-root.mdx) | Options to be merged before popping the screen (optional). |

```js
Navigation.popTo(componentId);
```

## `setStackRoot()`
Reset the stack to the given layout (accepts multiple children).

#### Parameters
| Name        | Required | Type                                                     | Description                                                           |
| ----------- | -------- | -------------------------------------------------------- | --------------------------------------------------------------------- |
| componentId | Yes      | string                                                   | The componentId of a screen pushed into the stack, or the stack id. |
| layout      | Yes      | [Layout](layout-layout.mdx) or [Layout](layout-layout.mdx)[] | A single Component or array of components.                            |


#### Example


<Tabs
  defaultValue='single'
  values={[
    { label: 'Single child', value: 'single' },
    { label: 'Multiple children', value: 'multiple' }
  ]
}>

<TabItem value='single'>

```js
Navigation.setStackRoot(this.props.componentId, {
  component: {
    name: 'example.NewRootScreen'
  }
});
```

</TabItem>

<TabItem value='multiple'>

In the example below we reset the stack with two components. The first one will be the root component and the second (`PushedScreen`) will be displayed. Pressing the back button (either hardware or software) will pop it, revealing the root component - `NewRootScreen`.

```js
Navigation.setStackRoot(this.props.componentId, [
  {
    component: {
      name: 'NewRootScreen',
    }
  },
  {
    component: {
      name: 'PushedScreen',
    }
  }
]);
```
</TabItem>

</Tabs>

---

### Api Layout BottomTabs (`website/docs/api/layout-BottomTabs.mdx`)

---
id: layout-bottomTabs
title: Bottom Tabs
sidebar_label: Bottom Tabs
---

A container view for managing a radio-style selection interface, where a selection determines which child view controller to display.

```js
{
  id: 'BOTTOM_TABS_LAYOUT',
  children: [
    {
      component: {
        id: 'HOME_SCREEN',
        name: 'HomeScreen'
      }
    },
    {
      stack: {
        id: 'PROFILE_TAB',
        children: [
          {
            component: {
              id: 'PROFILE_SCREEN',
              name: 'ProfileScreen'
            }
          }
        ]
      }
    }
  ]
}
```

## `id`

| Type   | Required | Description                                                                                                                                                    |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| string | No       | Unique id used to interact with the view via the Navigation api, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. |

## `children`

| Type               | Required | Description                   |
| ------------------ | -------- | ----------------------------- |
| [Layout[]](layout-layout.mdx) | YES      | Child layouts of any kind. |

## `options`

| Type                    | Required | Description                                                   |
| ----------------------- | -------- | ------------------------------------------------------------- |
| [Options](options-root.mdx) | No       | dynamic options which will apply to all screens in bottomTabs |

---

### Api Layout Component (`website/docs/api/layout-component.mdx`)

---
id: layout-component
title: Component
sidebar_label: Component
---

```js
{
  name: "MyRegisteredComponent";
}
```

## `name`

| Type   | Required | Description                                                                      |
| ------ | -------- | -------------------------------------------------------------------------------- |
| string | Yes      | Key used when registering the component with `Navigation.registerComponent`. |

## `id`

| Type   | Required | Description                                                                                                                                                    |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| string | No       | Unique id used to interact with the view via the Navigation api, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. |

## `options`

| Type                    | Required | Description                       |
| ----------------------- | -------- | --------------------------------- |
| [Options](options-root.mdx) | No       | dynamic options for the component |

## `alignment`

| Type                   | Required | Description                                                                                                                                                                                                                                                                         |
| ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| enum('center', 'fill') | No       | This option is relevant only to title components. `fill` will make the component stretch and consume all available space in the TopBar while `center` will center it in the middle of the TopBar. `center` is the default option in iOS while `fill` is the default for Android. |

## `waitForRender`

| Type    | Required | Description                                                        |
| ------- | -------- | ------------------------------------------------------------------ |
| boolean | No       | Wait for this component to fully render before showing the screen. |

This option is useful for ensuring that both a child screen pushed into the stack and all of the TopBar components (title, background and buttons) are displayed to the user at the same time.

To enable this option, `waitForRender` in the relevant screen animation option needs to be enabled as well.

:::caution
This option might introduce delays when pushing screens and should be used with caution.
:::

## `passProps`

| Type   | Required | Description                                                                        |
| ------ | -------- | ---------------------------------------------------------------------------------- |
| object | No       | A JavaScript object with props accessible inside the component using `this.props`. |

---

### Api Layout Layout (`website/docs/api/layout-layout.mdx`)

---
id: layout-layout
title: Layout
sidebar_label: Layout
---

## `id`

| Type   | Required | Description                                                                                                                                                    |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| string | No       | Unique id used to interact with the view via the Navigation API, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. |

## `options`

| Type                    | Required | Description                    |
| ----------------------- | -------- | ------------------------------ |
| [Options](options-root.mdx) | No       | dynamic options for the layout |

## `children`

| Type               | Required | Description                   |
| ------------------ | -------- | ----------------------------- |
| [Layout[]](layout-layout.mdx) | Yes      | Child layouts of any kind. |

---

### Api Layout SideMenu (`website/docs/api/layout-sideMenu.mdx`)

---
id: layout-sideMenu
title: Side Menu
sidebar_label: Side Menu
---

This layout allows implementing sidemenus, which can be opened by swiping from one side towards the other side.

```js
{
  left: {
    component: {}
  },
  center: {
    stack: {
      options: {},
      children: [{
        component: {}
      }]
    }
  },
  right: {
    component: {}
  }
}
```

## `center`

| Type             | Required | Description                                      |
| ---------------- | -------- | ------------------------------------------------ |
| [Layout](layout-layout.mdx) | Yes      | Center component, contains the main application. |

## `left`

| Type             | Required | Description                        |
| ---------------- | -------- | ---------------------------------- |
| [Layout](layout-layout.mdx) | No       | Contains the left component layout. |

## `right`

| Type             | Required | Description                         |
| ---------------- | -------- | ----------------------------------- |
| [Layout](layout-layout.mdx) | No       | Contains the right component layout. |

---

### Api Layout SplitView (`website/docs/api/layout-splitView.mdx`)

---
id: layout-splitView
title: SplitView
sidebar_label: SplitView
---

A container view controller implementing a master-detail interface. See [UISplitViewController docs](https://developer.apple.com/documentation/uikit/uisplitviewcontroller).
Currently implemented only in iOS.

```js
{
  id: 'PROFILE_TAB',
  master: {
    component: {
      id: 'MASTER_SCREEN',
      name: 'MasterScreen'
    }
  },
  detail: {
    component: {
      id: 'DETAIL_SCREEN',
      name: 'DetailScreen'
    }
  }
}
```

## `id`

| Type   | Required | Description                                                                                                                                                    |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| string | No       | Unique id used to interact with the view via the Navigation api, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. |

## `master`

| Type               | Required | Description                                     |
| ------------------ | -------- | ----------------------------------------------- |
| [Layout](layout-layout.mdx) | YES      | Set master layout (the smaller screen, sidebar) |

## `detail`

| Type               | Required | Description                                   |
| ------------------ | -------- | --------------------------------------------- |
| [Layout](layout-layout.mdx) | YES      | Set detail layout (the larger screen, flexes) |

## `options`

| Type                    | Required | Description                                     |
| ----------------------- | -------- | ----------------------------------------------- |
| [Options](options-root.mdx) | No       | dynamic options which will apply to all screens |

---

### Api Layout Stack (`website/docs/api/layout-stack.mdx`)

---
id: layout-stack
title: Stack
sidebar_label: Stack
---

A stack is a container layout promoting a hierarchical navigation. It is used to navigate between screens at consecutive levels of hierarchy, steps in a flow or across an app.

```js
{
  id: 'PROFILE_TAB',
  children: [
    {
      component: {
        id: 'PROFILE_SCREEN',
        name: 'ProfileScreen'
      }
    }
  ]
}
```

## `id`

| Type   | Required | Description                                                                                                                                                    |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| string | No       | Unique id used to interact with the view via the Navigation api, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. |

## `children`

| Type               | Required | Description                   |
| ------------------ | -------- | ----------------------------- |
| [Layout[]](layout-layout.mdx) | YES      | Child layouts of any kind. |

## `options`

| Type                    | Required | Description                                              |
| ----------------------- | -------- | -------------------------------------------------------- |
| [Options](options-root.mdx) | No       | Options that will apply to all screens in stack |

---

### Api Options Animations (`website/docs/api/options-animations.mdx`)

---
id: options-animations
title: Animations
sidebar_label: Animations
---

---

### Api Options BackButton (`website/docs/api/options-backButton.mdx`)

---
id: options-backButton
title: Back Button Options
sidebar_label: Back Button
---

Controls the back button styling.

```js
const options = {
  topBar: {
    backButton: {},
  },
};
```

### `accessibilityLabel`

Overrides the text that's read by the screen reader when the user interacts with the back button.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Android  |

### `id`

Button id for reference press event.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Android  |

### `color`

Change the back button color. This will change the text color as well.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

### `icon`

Change the default back button icon.

| Type                                       | Required | Platform |
| ------------------------------------------ | -------- | -------- |
| [ImageResource](options-imageResource.mdx) | No       | Both     |

### `sfSymbol`

SF Symbol to show as the back button

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS 13+  |

### `showTitle`

Show or hide the text displayed next to the back button.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | iOS      |

### `displayMode`

Set display mode of the back button. Currently works for iOS 14+ only.
See: [UINavigationItem.BackButtonDisplayMode
](https://developer.apple.com/documentation/uikit/uinavigationitem/backbuttondisplaymode)

| Type                                  | Required | Platform |
| ------------------------------------- | -------- | -------- |
| enum('default', 'generic', 'minimal') | No       | iOS      |

### `title`

Change the text displayed next to the title. Usually the back button shows the title of the previous screen.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS      |

### `visible`

Hide or show the back button.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `testID`

Used to interact with the back button in e2e tests.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `enableMenu`

Enables iOS 14 back button menu display.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | iOS      | true    |

### `popStackOnPress`

Controls whether the default back button should pop screen or not.

| Type    | Required | Default |
| ------- | -------- | ------- |
| boolean | No       | true    |

### `hideSharedBackground`

Hide the shared Liquid-Glass / Platter background that UIKit draws behind the back button starting with iOS 26. RNN defaults this to `true` when the back button uses an [`iconBackground`](options-iconBackground.mdx) so the system Platter does not double-decorate it. Set to `false` to keep the system-drawn background.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | iOS 26+  | true    |

---

### Api Options Background (`website/docs/api/options-background.mdx`)

---
id: options-background
title: Background Options
sidebar_label: Background
---

Controls the top bar background styling.

```js
const options = {
  topBar: {
    background: {}
  }
};
```

### `color`

Set the background color. Ignored if a component is specified.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `component`

Set a react [component](layout-component.mdx) as the background. Useful when you need to show a gradient as background, for instance.


On Android, setting an `id` to the Component will prevent the component from being recreated each time it's used by a screen. The component will be created once and whenever possible it will be reused.

| Type                   | Required | Platform |
| ---------------------- | -------- | -------- |
| [Component](layout-component.mdx) | No       | Both     |

### `clipToBounds`

Clip the top bar background to bounds if set to true.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `translucent`

Allows the NavBar to be translucent (blurred).

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `blur`

Enable background blur.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

---

### Api Options BottomTab (`website/docs/api/options-bottomTab.mdx`)

---
id: options-bottomTab
title: Bottom Tab Options
sidebar_label: Bottom Tab
---

```js
const options = {
  bottomTab: {},
};
```

Recommended: [Custom bottom tabs guide](../docs/docs-customBottomTabs.mdx) for React tab items and examples.

## `component`

Render a registered React component as the tab item content (icon + label area).

| Type | Required | Platform |
| ---- | -------- | -------- |
| object | No | Both |

```js
bottomTab: {
  component: {
    name: 'MyTabItem',
    passProps: { /* optional, merged at creation */ },
  },
}
```

**Requirements:** Every tab in the same `bottomTabs` layout must declare `component`, or RNN falls back to native rendering for all tabs.

**Props delivered to the component:** `componentId`, `tabIndex`, `selected`, `badge` (updated when selection/badge changes).

**Ignored when set:** `text`, `icon`, `selectedIcon`, `sfSymbol`, `sfSelectedSymbol`, `iconColor`, `selectedIconColor`, `iconWidth`, `iconHeight`, `iconInsets`, `fontFamily`, `fontWeight`, `fontSize`, `selectedFontSize`, `textColor`, `selectedTextColor`.

Native still owns selection, visibility, `drawBehind`, animations, and `dotIndicator`. Pair with [`bottomTabs.customRow`](options-bottomTabs.mdx#customrow) to style the floating row.

Tab press and selection [events](events) match native bottom tabs; long press is not available on custom items. See [Custom bottom tabs — Events](../docs/docs-customBottomTabs.mdx#events).

## `selectTabOnPress`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

## `popToRoot`

Pop to root of stack by tapping on already selected tab.

| Type    | Required | Platform  |
| ------- | -------- | --------- |
| boolean | No       | Android   |

## `badge`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

## `badgeColor`

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

## `animateBadge`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `disableIconTint`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

## `dotIndicator`

| Type         | Required | Platform |
| ------------ | -------- | -------- |
| DotIndicator | No       | Both     |

## `fontFamily`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

## `fontStyle`

| Type                     | Required | Platform |
| ------------------------ | -------- | -------- |
| enum('normal', 'italic') | No       | Both     |

## `fontWeight`

| Type                                                                                  | Required | Platform |
| ------------------------------------------------------------------------------------- | -------- | -------- |
| enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') | No       | Both     |

## `fontSize`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

## `icon`

| Type                                       | Required | Platform |
| ------------------------------------------ | -------- | -------- |
| [ImageResource](options-imageResource.mdx) | No       | Both     |

## `iconWidth`

The width (in dp) of the icon.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

## `iconHeight`

The height (in dp) of the icon.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

## `iconColor`

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

## `selectedFontSize`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

## `selectedIcon`

| Type                                       | Required | Platform |
| ------------------------------------------ | -------- | -------- |
| [ImageResource](options-imageResource.mdx) | No       | Both     |

## `selectedIconColor`

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

## `iconInsets`

| Type       | Required | Platform |
| ---------- | -------- | -------- |
| IconInsets | No       | Both     |

## `disableSelectedIconTint`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `disableIconTint`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `selectedTextColor`

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

## `testID`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `accessibilityLabel`

Overrides the text that's read by the screen reader when the user interacts with the bottomTab button.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS      |

## `text`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

## `textColor`

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

### `sfSymbol`

Set the SF symbol as icon (will be used primarily).

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS 13+  |


### `sfSelectedSymbol`

Set the SF symbol as selected icon (will be used primarily)

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS 13+  |

## DotIndicator

##### color?: color

##### size?: number

##### visible?: boolean

##### animate?: boolean

## IconInsets

##### top?: number

##### left?: number

##### right?: number

##### bottom?: number

---

### Api Options BottomTabs (`website/docs/api/options-bottomTabs.mdx`)

---
id: options-bottomTabs
title: Bottom Tabs Options
sidebar_label: Bottom Tabs
---

Recommended: Read about Bottom Tabs in the [Bottom Tabs Guide](../docs/docs-bottomTabs.mdx). For React tab items, see [Custom bottom tabs](../docs/docs-customBottomTabs.mdx).

```js
const options = {
  bottomTabs: {},
};
```

## `customRow`

Visual options for the floating row that hosts custom React tab cells. **Only applies when every tab uses [`bottomTab.component`](options-bottomTab.mdx#component).**

| Type | Required | Platform |
| ---- | -------- | -------- |
| [BottomTabsCustomRowOptions](#bottomtabscustomrowoptions) | No | Both |

```js
bottomTabs: {
  customRow: {
    height: 67,
    backgroundEffect: 'glass',
    cornerRadius: 28,
    horizontalMargin: 16,
    bottomMargin: 0,
  },
}
```

On Android, `customRow` is forwarded from JS via `RNNBottomTabsCustomRowModule` (no change to existing `BottomTabs` layout code). On iOS, options are parsed natively from the layout tree.

### BottomTabsCustomRowOptions

#### `height`

Content height of the row in points (iOS) / dp (Android). Excludes safe-area inset.

| Type | Required | Platform |
| ---- | -------- | -------- |
| number | No | Both |

Default: native tab content height; on iOS 26+ an extra 18pt is added when `height` is omitted.

**Total visible row height** = `height` + safe-area bottom + `bottomMargin`.

#### `backgroundColor`

Solid row background. When set, overrides `backgroundEffect`.

| Type | Required | Platform |
| ---- | -------- | -------- |
| color | No | Both |

#### `backgroundEffect`

| Type | Required | Platform |
| ---- | -------- | -------- |
| enum(`glass`, `blur`, `none`) | No | Both |

| Value | iOS | Android |
| ----- | --- | ------- |
| `glass` | `UIGlassEffect` on iOS 26+, blur fallback | Semi-opaque material chrome |
| `blur` | `UIBlurEffect` systemChromeMaterial | Semi-opaque material chrome |
| `none` | Transparent | Transparent |

Default: `glass` on iOS 26+, `blur` on older iOS.

#### `cornerRadius`

Corner radius of the row background.

| Type | Required | Platform |
| ---- | -------- | -------- |
| number | No | Both |

Default: `28` on iOS 26+, `0` on older iOS / when omitted on Android until configured.

#### `horizontalMargin`

Horizontal inset from the screen edges.

| Type | Required | Platform |
| ---- | -------- | -------- |
| number | No | Both |

Default: `16` on iOS 26+, `0` when omitted.

#### `bottomMargin`

Distance between the row's bottom edge and the safe-area bottom.

| Type | Required | Platform |
| ---- | -------- | -------- |
| number | No | Both |

Default: `0`.

## `animate`

Controls whether toggling visibility states will be animated.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

## `animateTabSelection`

Controls wether tab selection is animated or not

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `backgroundColor`

Specify the background color.
On Android - also applicable when translucence is applied, but a semi-transparent color should be used (e.g. `rgba(255, 0, 0, 0.25)`).

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Both     |

## `barStyle`

Controls whether the BottomTabs use dark (black) or light (default) visual style. Requires `translucent: true`.

| Type                    | Required | Platform |
| ----------------------- | -------- | -------- |
| enum('default','black') | No       | Both     |

## `layoutStyle`

Control the way the bottom tabs are laid out.
- `stretch`: Fill the entire width of the screen.
- `compact`: Occupy the minimum width needed to hold tab buttons. Recommended for usage in conjunction with `drawBehind: true`.

| Type                      | Required | Platform |
| ------------------------- | -------- | -------- |
| enum('stretch','compact') | No       | Android  |

## `currentTabId`

Select a tab by the id (componentId) of a child contained in it. See [Selecting tabs programmatically](#selectingtabsprogrammatically) for a detailed explanation.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

## `currentTabIndex`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

## `drawBehind`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

## `elevation`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

## `cornerRadius`

Specify a corner-radius in order to apply round corners to the tabs container.
Mainly suitable when used in conjunction with `layoutStyle: 'compact'`

| Type        | Required | Platform |
| ----------- | -------- | -------- |
| number(dip) | No       | Android  |

## `bottomMargin`

Bottom-margin to set in order to enable a "hover" effect.
Works best when used in conjunction with `layoutStyle: 'compact'` and `drawBehind: true`.

| Type        | Required | Platform |
| ----------- | -------- | -------- |
| number(dip) | No       | Android  |

## `hideShadow`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

## `hideOnScroll`

Hides the BottomTabs on scroll to increase the amount of content visible to the user.
The options requires that the scrollable view will be the root view of the screen and that it specifies `nestedScrollEnabled: true`.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `preferLargeIcons`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

## `tabsAttachMode`

| Type                                               | Required | Platform |
| -------------------------------------------------- | -------- | -------- |
| enum('together','afterInitialTab','onSwitchToTab') | No       | Both     |

## `testID`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

## `titleDisplayMode`

| Type                                             | Required | Platform |
| ------------------------------------------------ | -------- | -------- |
| enum('alwaysShow','showWhenActive','alwaysHide') | No       | Both     |

## `translucent`

A Boolean value that indicates whether the BottomTabs should be translucent (and background-blurred).
For this option to function properly the screen needs to be drawn behind the BottomTabs; Make sure the list component you're using (FlatList for example) is the root component in the screen and not SafeAreaView. When SafeAreView is the root component it shifts the content above the BottomTabs and the translucent effect isn't visible.

Note: On Android, the option is experimental and should be enabled using a native feature-toggle called `TAB_BAR_TRANSLUCENCE` (pass it to your `NavigationApplication` class' c'tor).

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS - Full support<br/>Android - Experimental |

## `blurRadius`

Set a custom radius to be used in the blur effect. Higher is blurrier, but also more CPU-intensive.
Note: The blurring is performed following a bitmap downscale of x4.0, so ultimately the actual radius is (4*blurRadius).

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |


## `visible`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

---

### Api Options Button (`website/docs/api/options-button.mdx`)

---
id: options-button
title: Button Options
sidebar_label: Button
---

```js
const options = {
  topBar: {
    leftButtons: [
      {
        id: 'id',
        text: 'Button',
      },
    ],
  },
};
```

### `allCaps`

This option will set whether characters are all capitalized or not.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | Android  | true    |

### `fontSize`

If the button has text, this option is used to set font size in DP.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `fontFamily`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `fontStyle`

| Type                     | Required | Platform |
| ------------------------ | -------- | -------- |
| enum('normal', 'italic') | No       | Both     |

### `fontWeight`

| Type                                                                                  | Required | Platform |
| ------------------------------------------------------------------------------------- | -------- | -------- |
| enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') | No       | Both     |

### `id`

Buttons are identified by their id property. When a button is clicked, a buttonPress event is emitted to js, containing the id of the clicked button.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | Yes      | Both     |

### `icon`

Button icon. If the button is pushed to the overflow menu, the button [text](#text) is used instead.

| Type                                       | Required | Platform |
| ------------------------------------------ | -------- | -------- |
| [ImageResource](options-imageResource.mdx) | No       | Both     |

### `sfSymbol`

SF Symbol to show as the back button

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS 13+  |

### `text`

Button text. Ignored if an icon is specified, unless the button is displayed in the overflow menu.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `showAsAction`

| Type                                          | Required | Platform |
| --------------------------------------------- | -------- | -------- |
| enum('always', 'never', 'withText', 'ifRoom') | No       | Android  |

- **ifRoom** - Only add button to the TopBar if there is room for it, otherwise add it to the overflow menu.
- **never** - Never place this button in the TopBar. Instead, list the button in the overflow menu.
- **always** - Always place this button in the app bar.

### `component`

Set a react [component](layout-component.mdx) as this button's view which will be displayed instead of the regular view.

| Type                              | Required | Platform |
| --------------------------------- | -------- | -------- |
| [Component](layout-component.mdx) | No       | Both     |

### `iconInsets`

[IconInsets](options-iconInsets.mdx) are applied to the icon to translate its original position on the screen.

| Type       | Required | Platform |
| ---------- | -------- | -------- |
| IconInsets | No       | iOS      |

### `systemItem`

System icon; ignored if an [icon](#icon-number) is specified. For more information, see [apple's guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/system-icons/).

| Type                                                                                                                                                                                                                                          | Required | Platform |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- |
| enum('done', 'cancel', 'edit', 'save', 'add', 'flexibleSpace', 'fixedSpace', 'compose', 'reply', 'action', 'organize', 'bookmarks', 'search', 'refresh', 'stop', 'camera', 'trash', 'play', 'pause', 'rewind', 'fastForward', 'undo', 'redo') | No       | iOS      |

### `iconBackground`

[iconBackground](options-iconBackground.mdx) is applied to the icon's background.

| Type           | Required | Platform |
| -------------- | -------- | -------- |
| iconBackground | No       | Both     |

### `hideSharedBackground`

Hide the shared Liquid-Glass / Platter background that UIKit draws behind every bar button item starting with iOS 26. RNN defaults this to `true` for buttons that paint their own chrome (custom react `component` views and icons with [`iconBackground`](options-iconBackground.mdx)) so the system Platter does not double-decorate them. Set to `false` to keep the system-drawn background.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | iOS 26+  | true    |

---

### Api Options Fab (`website/docs/api/options-fab.mdx`)

---
id: options-fab
title: Fab
sidebar_label: Fab
---

Controls the FAB button styling on Android.

```js
const options = {
  fab: {
    id: 'id',
    icon: require('path-to-fab-icon'),
    backgroundColor: 'coral',
    actions: [
      {
        id: 'id2',
        icon: require('path-to-fab-icon-2),
      }
    ]
  },
};
```

### `id`

Button id for reference press event.

:::info Note
This option is mandatory when you are initiating the FAB button. However you do not need to pass in `id` when updating the Fab button options with `Navigation.mergeOptions`.
:::

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Android  |

### `icon`

Change the default back button icon.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `iconColor`

Change the icon color of the FAB button.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Android  |

### `backgroundColor`

Change the background color of the FAB button.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Android  |

### `clickColor`

Change the on-clicked background color of the FAB button.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Android  |

### `rippleColor`

Change the ripple color of the FAB button.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| color | No       | Android  |

### `visible`

Show or hide the FAB button.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

### `alignHorizontally`

Set the horizontal position of the FAB button on the screen.

| Type              | Required | Platform |
| ----------------- | -------- | -------- |
| 'left' or 'right' | No       | Android  |

### `hideOnScroll`

Hide the FAB button on scroll.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

### `size`

Set the size of the FAB button.

| Type                | Required | Platform |
| ------------------- | -------- | -------- |
| 'mini' or 'regular' | No       | Android  |

---

### Api Options HardwareBackButton (`website/docs/api/options-hardwareBackButton.mdx`)

---
id: options-hardwareBackButton
title: Hardware Back Button Options
sidebar_label: Hardware Back Button
---

Controls Android hardware back button.

```js
const options = {
  hardwareBackButton: {},
};
```

### `dismissModalOnPress`

Controls whether the hardware back button should dismiss modal or not.

| Type    | Required | Default | Platform |
| ------- | -------- | ------- | -------- |
| boolean | No       | true    | Android  |

### `popStackOnPress`

Controls whether the hardware back button should pop stacks or not.

| Type    | Required | Default | Platform |
| ------- | -------- | ------- | -------- |
| boolean | No       | true    | Android  |


### `bottomTabsOnPress`

Controls hardware back button bottom tab selection behaviour,
`first` will jump to first tab,
`previous` will do reverse selection,
`exit` (Default) will just exit the bottom tabs.

| Type                             | Required | Default   | Platform |
| -------------------------------- | -------- | --------- | -------- |
| enum('exit', 'first', 'previous') | No       | 'exit'    | Android  |

---

### Api Options IconBackground (`website/docs/api/options-iconBackground.mdx`)

---
id: options-iconBackground
title: iconBackground Options
sidebar_label: iconBackground
---

### `color`

Set the background color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `width`

Set the background width.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `height`

Set the background height.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `cornerRadius`

Set the background cornerRadius.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

---

### Api Options IconInsets (`website/docs/api/options-iconInsets.mdx`)

---
id: options-iconInsets
title: IconInsets Options
sidebar_label: IconInsets
---

### `top`

Configure top inset

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `bottom`

Configure bottom inset

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `left`

Configure left inset

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `right`

Configure right inset

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

---

### Api Options ImageResource (`website/docs/api/options-imageResource.mdx`)

---
id: options-imageResource
title: Image Resource
sidebar_label: Image Resource
---

## `ImageResource`

```js
const options = {
  topBar: {
    leftButtons: [
        icon: require('./backButton.png')
    ]
  },
};
```

The following icon types are available:

| Type   | Required | Platform |
| ------ | -------- | -------- |
| ImageRequireSource | No       | Both     |
| string | No       | Both     |
| [ImageSystemSource](#imagesystemresource) | No | iOS |


## `ImageSystemSource`

### `system`

You can use platform specific system icons for [iOS only](https://developer.apple.com/sf-symbols/).

Example:

```js
const options = {
  topBar: {
    leftButtons: [
        icon: {
            system: 'calendar',
            fallback: require('./calendar.png')
        }
    ]
  },
};
```

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | Yes       | iOS 13+     |

### `fallback`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| [FallbackSource](#fallbacksource) | No       |  iOS 13+     |


## `FallbackSource`

For iOS, SF Symbols is available only for iOS 13 and later. For iOS 12 and earlier you should use a fallback icon.

### `ImageRequireSource`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `string`

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

---

### Api Options LargeTitle (`website/docs/api/options-largeTitle.mdx`)

---
id: options-largeTitle
title: Large Title Options
sidebar_label: Large Title
---

Controls the top bar large title on iOS, available on iOS 11 and above.

```js
const options = {
  topBar: {
    largeTitle: {},
  },
};
```

### `visible`

Controls whether the large title is visible or not.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `fontSize`

Set the title font size. On Android this value is in `sp`.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | iOS      |

### `color`

Large title text color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | iOS      |

### `fontFamily`

Set the large title [FontFamily](../docs/style-fonts.mdx).

| Type       | Required | Platform |
| ---------- | -------- | -------- |
| FontFamily | No       | iOS      |

### `fontStyle`

| Type                     | Required | Platform |
| ------------------------ | -------- | -------- |
| enum('normal', 'italic') | No       | iOS      |

### `fontWeight`

| Type                                                                                  | Required | Platform |
| ------------------------------------------------------------------------------------- | -------- | -------- |
| enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') | No       | iOS      |

---

### Api Options Layout (`website/docs/api/options-layout.mdx`)

---
id: options-layout
title: Layout Options
sidebar_label: Layout
---

```js
const options = {
  layout: {},
};
```

### `fitSystemWindows`

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `backgroundColor`

Set the screen background color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `componentBackgroundColor`

Set background color only for components. On Android, using this option instead of `backgroundColor` helps reduce overdraw.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `orientation`

Set the allowed orientations.

| Type                      | Required | Platform |
| ------------------------- | -------- | -------- |
| ['portrait', 'landscape'] | No       | Both     |

### `topMargin`

Set the layout top margin.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `direction`

Set language direction, only works with DefaultOptions. `locale` is an Android specific option which sets the direction according to the device locale.

| Type                         | Required | Platform |
| ---------------------------- | -------- | -------- |
| enum('rtl', 'ltr', 'locale') | No       | Both     |

### `autoHideHomeIndicator`

Controls the application's preferred home indicator auto-hiding.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

---

### Api Options Migration (`website/docs/api/options-migration.mdx`)

# Common Options

## navBarTextColor
Title text color

```js
topBar: {
  title: {
    color: 'red'
  }
}
```

## navBarTextFontSize
Title font size

```js
topBar: {
  title: {
    fontSize: 18
  }
}
```

## navBarTextFontFamily
Title font

```js
topBar: {
  title: {
    fontFamily: 'Helvetica'
  }
}
```

## navBarBackgroundColor
TopBar background color

```js
topBar: {
  background: {
    color: 'red'
  }
}
```

## navBarCustomView
Use a react view as the TopBar's background or use a React view instead of the textual title.

```js
topBar: {
  background: {
    component: {
      name: 'example.CustomTopBarBackground'
    }
  },
  title: {
    component: {
      name: 'example.CustomTopBarTitle'
    }
  }
}
```

## navBarClipToBounds
Restrict the navbar background color to the navbar, and do not flow behind the status bar.

```js
topBar: {
  background: {
    component: {
      name: 'example.CustomTopBarBackground',
      clipToBounds: true
    }
  },
}
```

## navBarComponentAlignment
Align the React view used as the title

```js
topBar: {
  title: {
    component: {
      name: 'example.CustomTopBarTitle',
      alignment: 'center' | 'fill'
    }
  }
}
```

## navBarCustomViewInitialProps
Initial props passed to the React component

```js
topBar: {
  background: {
    component: {
      name: 'example.CustomTopBarBackground',
      passProps: {}
    }
  },
  title: {
    component: {
      name: 'example.CustomTopBarTitle',
      passProps: {}
    }
  }
}
```

## navBarButtonColor
TopBar button color

```js
topBar: {
  rightButtons: [
    {
      color: 'red'
    }
  ],
  leftButtons: [
    {
      color: 'red'
    }
  ],
  backButton: {
    color: 'red'
  }
}
```

## navBarHidden
TopBar visibility. When setting `visible: false`, you probably want to set `drawBehind: true` as well. Use `animate: false` to toggle visibility without animation.

```js
topBar: {
  visible: false
}
```

## navBarTransparent
Transparent TopBar. Set `drawBehind: true` to draw the screen behind the transparent TopBar.

```js
topBar: {
  background: {
    color: 'transparent'
  }
}
```

## drawUnderNavBar
Draw the screen behind the TopBar, Useful when the TopBar is toggled or transparent

```js
topBar: {
  drawBehind: true
}
```

## drawUnderTabBar
Draw the screen behind the BottomTabs, Useful when toggling BottomTabs or when the BottomTabs are translucent.

```js
bottomTabs: {
  drawBehind: true
}
```

## tabBarHidden
BottomTabs visibility.
```js
bottomTabs: {
  visible: false
}
```

The BottomTab's visibility can be toggled only on **Android** using `mergeOptions`:
```js
Navigation.mergeOptions(this.props.componentId, {
  bottomTabs: {
    visible: false
  }
});
```
On **iOS**, BottomTab visibility can be changed only when pushing screens. This means that if you'd like to hide BottomTabs when pushing a screen, You'll need to set the property to `false` in the options passed to the `push` command or via the `static options(passProps) {}` api.

## statusBarHidden
StatusBar visibility. For android, also set `drawBehind: true`.

```js
statusBar: {
  visible: false
}
```

## statusBarTextColorScheme
Theme of text and icons displayed in the StatusBar

```js
statusBar: {
  style: 'light' | 'dark'
}
```

## navBarSubtitleColor
Subtitle color

```js
topBar: {
  subtitle: {
    color: 'red'
  }
}
```

## navBarSubtitleFontFamily
Subtitle font

```js
topBar: {
  subtitle: {
    fontFamily: 'Helvetica'
  }
}
```

## navBarSubtitleFontSize
Subtitle font size

```js
topBar: {
  subtitle: {
    fontSize: 14
  }
}
```

## screenBackgroundColor
Screen color, visible before the actual React view is rendered

```js
layout: {
  backgroundColor: 'red'
}
```

## orientation

```js
layout: {
  orientation: ['portrait', 'landscape'] // An array of supported orientations
}
```

## disabledButtonColor
Button color when `enabled: false` is used

```js
topBar: {
  rightButtons: [
    {
      disabledColor: 'grey'
    }
  ]
}
```

## navBarButtonFontSize
Button font size

```js
topBar: {
  rightButtons: [
    {
      fontSize: 13
    }
  ],
  leftButtons: [
    {
      fontSize: 13
    }
  ]
}
```

## navBarLeftButtonFontSize
Left button font size

```js
{
  topBar: {
    leftButtons: [
      {
        fontSize: 13
      }
    ]
  }
}
```

## navBarLeftButtonColor
Left button color

```js
{
  topBar: {
    leftButtons: [
      {
        color: 'red'
      }
    ]
  }
}
```

## navBarLeftButtonFontWeight
Left button font weight

```js
{
  topBar: {
    leftButtons: [
      {
        weight: '300'
      }
    ]
  }
}
```

## navBarRightButtonFontSize
Right button font size

```js
topBar: {
  leftButtons: [
    {
      fontSize: 13
    }
  ]
}
```

## navBarRightButtonColor
Right button color

```js
topBar: {
  rightButtons: [
    {
      color: 'red'
    }
  ]
}
```

## navBarRightButtonFontWeight
Right button font weight

```js
topBar: {
  rightButtons: [
    {
      weight: '400'
    }
  ]
}
```

## modalPresentationStyle
Controls the behavior of screens displayed modally.

### Options supported on iOS
* `overCurrentContext` - Content is displayed over the previous screen. Useful for **transparent modals**
* `formSheet` - Content is centered in the screen
* `pageSheet` -Content partially covers the underlying content
* `overFullScreen` - Content covers the screen, without detaching previous content.
* `fullScreen` - Content covers the screen, previous content is detached.
* `popover` - Content is displayed in a popover view.

More information on the different styles for iOS can be found on https://developer.apple.com/documentation/uikit/uimodalpresentationstyle

### Options supported on Android
* `overCurrentContext` - Content is displayed over the previous screen. Useful for **transparent modals**
* `none` - Previous content is detached when the Modal's show animation ends

```js
{
  modalPresentationStyle: 'overCurrentContext'
}
```

## navBarButtonFontFamily
Button font family

```js
topBar: {
  rightButtons: [
    {
      fontFamily: 'Helvetica'
    }
  ]
}
```

# iOS only

## navBarHideOnScroll
Hide TopBar when list is scrolled

```js
topBar: {
  hideOnScroll: true
}
```

## navBarTranslucent
Translucent TopBar, Setting `drawBehind: true` is required for this property to work as expected.

```js
topBar: {
  drawBehind: true,
  background: {
    translucent: true
  }
}
```

## navBarNoBorder
Remove TopBar border (hair line)

```js
topBar: {
  noBorder: true
}
```

## navBarBlur
Blur the area behind the TopBar, Setting `drawBehind: true` and  topBar background `transparent: true` is required for this property to work as expected.

```js
topBar: {
  drawBehind: true,
  background: {
    blur: true,
    transparent: true
  }
}
```

## rootBackgroundImageName

* iOS: name of image in Images.xcassets
* Android: name of drawable

```js
{
  rootBackgroundImage: require('rootBackground.png')
}
```

## screenBackgroundImageName
name of image in Images.xcassets

```js
{
  backgroundImage: require('background.png')
}
```

## statusBarHideWithNavBar
Hide the StatusBar if the TopBar is also hidden

```js
statusBar: {
  hideWithTopBar: true
}
```

## statusBarBlur
Blur the area behind the StatusBar

```js
statusBar: {
  blur: true
}
```

## statusBarAnimate
Animate between style changes of the StatusBar

```js
statusBar: {
  animate: true
}
```

## disabledBackGesture
Disable the back (swipe) gesture used to pop screens

```js
{
  popGesture: false
}
```

## largeTitle
Use iOS 11 large title

```js
  topBar: {
    largeTitle: {
      visible: true,
      fontSize: 30,
      color: 'red',
      fontFamily: 'Helvetica'
    }
  }
```

# Android Options

## topBarElevationShadowEnabled
TopBar elevation in dp. Set this value to `0` to disable the TopBar's shadow.

```js
topBar: {
  elevation: 0
}
```

## navBarTitleTextCentered
Title alignment

```js
topBar: {
  title: {
    alignment: 'center'|'fill'
  }
}
```

## statusBarColor
StatusBar color

```js
statusBar: {
  backgroundColor: 'red'
}
```

## navigationBarColor
NavigationBar color

```js
navigationBar: {
  backgroundColor: 'red'
}
```

## drawUnderStatusBar
Draw content behind the StatusBar

```js
statusBar: {
  drawBehind: true
}
```

## navBarHeight
TopBar height in dp

```js
topBar: {
  height: 70
}
```

## navBarTopPadding
Content top margin

```js
layout: {
    topMargin: 26
  }
```

## topTabsHeight
TopTabs height

```js
topTabs: {
  height: 70
}
```

## topBarBorderColor
TopBar border color

```js
topBar: {
  borderColor: 'red'
}
```

## topBarBorderWidth
TopBar border height

```js
topBar: {
  borderHeight: 1.3
}
```

# Unsupported options
* disabledSimultaneousGesture
* statusBarTextColorSchemeSingleScreen
* navBarButtonFontWeight
* topBarShadowColor
* topBarShadowOpacity
* topBarShadowOffset
* topBarShadowRadius
* preferredContentSize
* navBarSubTitleTextCentered
* collapsingToolBarImage
* collapsingToolBarCollapsedColor
* navBarTextFontBold

---

### Api Options Modal (`website/docs/api/options-modal.mdx`)

---
id: options-modal
title: Modal Options
sidebar_label: Modal
---

```js
const options = {
  swipeToDismiss
};
```

## `swipeToDismiss`

Control wether this modal should be dismiss using swipe gesture when the `modalPresentationStyle` is `pageSheet`

| Type                                  | Required | Platform |  Default |
| ------------------------------------- | -------- | -------- | -------- |
| boolean                               | No       | Both     | true     |

---

### Api Options NavigationBar (`website/docs/api/options-navigationBar.mdx`)

---
id: options-navigationBar
title: Navigation Bar Options
sidebar_label: Navigation Bar
---
import useBaseUrl from '@docusaurus/useBaseUrl';

The Navigation Bar is the area at the bottom of the screen containing Android's three navigation buttons: Back, Home and Recents.

:::info Edge-to-Edge
Starting with Android 15 (API 35), the system enforces edge-to-edge by default. React Native Navigation supports this via a theme opt-in. See the [Edge-to-Edge guide](../docs/style-edge-to-edge) for setup instructions. Navigation bar options below work in both edge-to-edge and non-edge-to-edge modes.
:::

An example of a dark navigation bar:
<img width="30%" src={useBaseUrl('/img/navBar_black.png')} />

<br></br>
<br></br>

```js
const options = {
  navigationBar: {}
};
```

### `visible`

Set the navigation bar visibility.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android     |

### `backgroundColor`

Set the navigation bar color. When a light background color is used, the color of the navigation bar icons will adapt to a dark color.

<img width="30%" src={useBaseUrl('/img/navBar_white.png')} />

| Type                  | Required | Platform | Default |
| --------------------- | -------- | -------- | ------- |
| Color | No       | Android     | 'black' |

### `drawBehind`

Draw screen content behind the system navigation bar while keeping it visible (gesture pill / 3-button bar remain on screen). Use with edge-to-edge enabled in your activity. With `backgroundColor: 'transparent'`, content shows through the nav bar area; with an opaque color, RNN paints a scrim overlay without reserving bottom layout inset.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

---

### Api Options Overlay (`website/docs/api/options-overlay.mdx`)

---
id: options-overlay
title: Overlay
sidebar_label: Overlay
---

Controls overlay options

```js
const options = {
  overlay: {

  }
}
```

### `interceptTouchOutside`
Controls whether touch events outside the bounds of the overlay are to be handled by content behind the overlay. When set to true, touch events will **not** pass through to the underlying content.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| boolean | No       | Both     |

### `handleKeyboardEvents`
Overlays on iOS don't handle keyboard events by default. If your Overlay contains a TextInput component, you'll want to enable this option so that TextInput responds to keyboard events.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| boolean | No       | iOS     |

---

### Api Options Preview (`website/docs/api/options-preview.mdx`)

---
id: options-preview
title: Preview (iOS)
sidebar_label: Preview (iOS)
---

---

### Api Options Root (`website/docs/api/options-root.mdx`)

---
id: options-root
title: The options object
sidebar_label: Options object
---

```js
const options = {
  bottomTab,
  bottomTabs,
  topBar,
  layout,
  sideMenu,
  overlay,
  modal,
  preview,
  navigationBar,
  scrollEdgeEffect,
};
```

## `bottomTab`

Controls the bottom tab icon, font, color, and more.

| Type                                  | Required | Platform |
| ------------------------------------- | -------- | -------- |
| [BottomTabOptions](options-bottomTab.mdx) | No       | Both     |

## `bottomTabs`

Controls the bottom tabs container.

| Type                                    | Required | Platform |
| --------------------------------------- | -------- | -------- |
| [BottomTabsOptions](options-bottomTabs.mdx) | No       | Both     |

## `topBar`

Controls the Stack top bar styling.

| Type                           | Required | Platform |
| ------------------------------ | -------- | -------- |
| [TopBarOptions](options-stack.mdx) |          | No       |

## `statusBar`

Controls the system status bar styling.

| Type                                  | Required | Platform |
| ------------------------------------- | -------- | -------- |
| [StatusBarOptions](options-statusBar.mdx) | No       | Both     |

## `layout`

| Type                            | Required | Platform |
| ------------------------------- | -------- | -------- |
| [LayoutOptions](options-layout.mdx) | No       | Both     |

## `sideMenu`

| Type                                | Required | Platform |
| ----------------------------------- | -------- | -------- |
| [SideMenuOptions](options-sideMenu.mdx) | No       | Both     |

## `overlay`

| Type                              | Required | Platform |
| --------------------------------- | -------- | -------- |
| [OverlayOptions](options-overlay.mdx) | No       | Both     |

## `animations`

| Type                                    | Required | Platform |
| --------------------------------------- | -------- | -------- |
| [AnimationsOptions](options-animations.mdx) | No       | Both     |

## `modal`

| Type                          | Required | Platform |
| ----------------------------- | -------- | -------- |
| [ModalOptions](options-modal.mdx) | No       | Both     |

## `preview`

| Type                              | Required | Platform |
| --------------------------------- | -------- | -------- |
| [PreviewOptions](options-preview.mdx) | No       | iOS      |

## `splitView`

| Type                                  | Required | Platform |
| ------------------------------------- | -------- | -------- |
| [SplitViewOptions](options-splitView.mdx) | No       | iOS      |

## `fab`

| Type               | Required | Platform |
| ------------------ | -------- | -------- |
| [Fab](options-fab.mdx) | No       | Android  |

## `modalPresentationStyle`

Configure the presentation style of the modal.

| Type                                                                                                    | Required | Platform |
| ------------------------------------------------------------------------------------------------------- | -------- | -------- |
| enum('formSheet', 'pageSheet', 'fullScreen', 'overFullScreen', 'overCurrentContext', 'popOver', 'none') | No       | Both     |

#### Styles supported on both platforms

- **overCurrentContext** - Display the modal and do not remove previous content when the show animation ends.
- **none** - default system presentation style

#### Styles supported only on iOS

- **fullScreen** - The view covers the underlying content completely.
- **pageSheet** - partially cover the underlying content.
- **formSheet** - display content centered in the screen.
- **overFullScreen** - display the modal in full screen mode and do not remove previous content when the show animation ends.
- **popOver** - Center content on screen and dim the content behind it.

The default presentation style is different on each platform.

| iOS                                                                                      | Android      |
| ---------------------------------------------------------------------------------------- | ------------ |
| <ul><li>iOS 12 and below - `fullScreen`</li><li>iOS 13 and above - `pageSheet`</li></ul> | `fullScreen` |

## `modalTransitionStyle`

Configure the transition style of the modal.

| Type                                                                    | Required | Platform |
| ----------------------------------------------------------------------- | -------- | -------- |
| enum('coverVertical', 'crossDissolve', 'flipHorizontal', 'partialCurl') | No       | Both     |

## `popGesture`

Enable or disable swipe back to pop gesture.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

## `navigationButtonEventOnSwipeBack`

Enable NavigationButtonPressed event sending on Swipe-back on pushed VC.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | iOS      | false   |

## `backgroundImage`

Background image of the screen.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Image | No       | iOS      |

## `rootBackgroundImage`

Background image for the Navigation View.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Image | No       | Android  |

## `blurOnUnmount`

Enable or disable automaticall blur of the focused input, dismissing keyboard on unmount.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | Android  | false   |

## `scrollEdgeEffect`

Show / hide or change the style of the iOS 26 scroll edge effect on every `UIScrollView` contained in the screen.

| Type                                                     | Required | Platform |
| -------------------------------------------------------- | -------- | -------- |
| [ScrollEdgeEffectOptions](options-scrollEdgeEffect.mdx)   | No       | iOS 26+  |

## `navigationBar`
Enable or disable automaticall blur of the focused input, dismissing keyboard on unmount.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

---

### Api Options ScrollEdgeAppearance (`website/docs/api/options-scrollEdgeAppearance.mdx`)

---
id: options-scrollEdgeAppearance
title: Scroll Edge Appearance Options
sidebar_label: Scroll Edge Appearance
---

Controls the top bar background styling.

```js
const options = {
  topBar: {
    scrollEdgeAppearance: {
      background: {},
      active: true,
    },
  },
};
```

### `active`

Since this might be considered as a breaking change (meaning that previous configs might behave different), you'll need to
pass active `true/false` to activate this option.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `color`

Set the background color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | iOS      |

### `translucent`

Allows the Scroll Edge Appearance to be translucent (blurred).

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `borderColor`

Change the topBar border color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | iOS      |

### `noBorder`

Disables border at the bottom of the TopBar.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

---

### Api Options ScrollEdgeEffect (`website/docs/api/options-scrollEdgeEffect.mdx`)

---
id: options-scrollEdgeEffect
title: Scroll Edge Effect Options
sidebar_label: Scroll Edge Effect
---

Controls the iOS 26+ `UIScrollEdgeEffect` (Liquid Glass fade) shown at the edges of scroll views when content scrolls under bars.

**Credits**: Contributed by [@manuhook](https://github.com/manuhook) ([PR #8281](https://github.com/wix/react-native-navigation/pull/8281)).

```js
const options = {
  scrollEdgeEffect: {
    hidden: true,
  },
};
```

### `hidden`

Hide the scroll edge effect.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS 26+  |

### `style`

Set the scroll edge effect style.

| Type                                | Required | Platform | Default     |
| ----------------------------------- | -------- | -------- | ----------- |
| enum('automatic', 'soft', 'hard')   | No       | iOS 26+  | 'automatic' |

### `top` / `bottom` / `left` / `right`

Per-edge override. Values fall back to the global `hidden` / `style`. Per-edge values take precedence.

| Type                                                                              | Required | Platform |
| --------------------------------------------------------------------------------- | -------- | -------- |
| `{ hidden?: boolean; style?: 'automatic' \| 'soft' \| 'hard' }`                    | No       | iOS 26+  |

## Examples

Hide all edges:

```js
MyScreen.options = {
  scrollEdgeEffect: { hidden: true },
};
```

Top visible, bottom hidden:

```js
MyScreen.options = {
  scrollEdgeEffect: {
    top: { hidden: false },
    bottom: { hidden: true },
  },
};
```

Dynamic update:

```js
Navigation.mergeOptions(componentId, {
  scrollEdgeEffect: { bottom: { hidden: true } },
});
```

---

### Api Options SideMenu (`website/docs/api/options-sideMenu.mdx`)

---
id: options-sideMenu
title: Side Menu Options
sidebar_label: Side Menu
---

```js
const options = {
  sideMenu: {
    left: {},
    right: {},
    openGestureMode: 'entireScreen',
  },
};
```

### `left`

Configure the left side menu.

| Type                                     | Required | Platform |
| ---------------------------------------- | -------- | -------- |
| [SideMenuSide](options-sideMenuSide.mdx) | No       | Both     |

### `right`

Configure the right side menu.

| Type                                     | Required | Platform |
| ---------------------------------------- | -------- | -------- |
| [SideMenuSide](options-sideMenuSide.mdx) | No       | Both     |

### `openGestureMode`

Configure how a user is allowed to open a drawer using gestures.

| Type                          | Required | Platform | Default |
| ----------------------------- | -------- | -------- | ------- |
| enum('entireScreen', 'bezel') | No       | iOS      | 'bezel' |

---

### Api Options SideMenuSide (`website/docs/api/options-sideMenuSide.mdx`)

---
id: options-sideMenuSide
title: Side Menu Side Options
sidebar_label: Side Menu Side
---

```js
const options = {
  sideMenu: {
    left: {
      visible: false,
      enabled: true
    }
  }
};
```

### `visible`

Show or hide the side menu.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `enabled`

Enable or disable the side menu.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `width`

Set the width of the side menu.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `height`

Set the height of the side menu.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

---

### Api Options SplitView (`website/docs/api/options-splitView.mdx`)

---
id: options-splitView
title: SplitView Options
sidebar_label: SplitView
---

### `displayMode`

Master view display mode.

| Type                                         | Required | Default | Platform |
| -------------------------------------------- | -------- | ------- | -------- |
| enum('auto', 'visible', 'hidden', 'overlay') | No       | 'auto'  | iOS      |

### `primaryEdge`

Master view side. Leading is left. Trailing is right.

| Type                        | Required | Default   | Platform |
| --------------------------- | -------- | --------- | -------- |
| enum('leading', 'trailing') | No       | 'leading' | iOS      |

### `minWidth`

Set the minimum width of master view.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | iOS      |

### `maxWidth`

Set the maximum width of master view.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | iOS      |

### `primaryBackgroundStyle`

Set background style of sidebar. Currently works for Mac Catalyst apps only.
See: [Optimizing Your iPad App for Mac
](https://developer.apple.com/documentation/uikit/mac_catalyst/optimizing_your_ipad_app_for_mac#3239145)

| Type                        | Required | Default   | Platform |
| --------------------------- | -------- | --------- | -------- |
| enum('none', 'sidebar')     | No       | 'none'    | iOS      |

---

### Api Options Stack (`website/docs/api/options-stack.mdx`)

---
id: options-stack
title: Top Bar Options
sidebar_label: Top Bar
---

## TopBar

```js
const options = {
  topBar: {
    animate: true,
    title: {},
    subtitle: {},
    backButton: {},
    background: {},
  },
};
```

### `visible`

Determines if TopBar is visible or not.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `animate`

Determines if changing the TopBar visibility will be animated or not.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `animateLeftButtons`

Determines if changing the left buttons will be animated.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | Both     | False   |

### `animateRightButtons`

Determines if changing the right buttons will be animated.

| Type    | Required | Platform | Default |
| ------- | -------- | -------- | ------- |
| boolean | No       | Both     | False   |

### `title`

Controls the top bar title.

| Type                       | Required | Platform |
| -------------------------- | -------- | -------- |
| [Title](options-title.mdx) | No       | Both     |

### `subtitle`

Controls the top bar subtitle.

| Type                            | Required | Platform |
| ------------------------------- | -------- | -------- |
| [Subitle](options-subtitle.mdx) | No       | Both     |

### `backButton`

Controls the top bar back button.

| Type                                 | Required | Platform |
| ------------------------------------ | -------- | -------- |
| [BackButton](options-backButton.mdx) | No       | Both     |

### `background`

Controls the top bar background.

| Type                                 | Required | Platform |
| ------------------------------------ | -------- | -------- |
| [Background](options-background.mdx) | No       | Both     |

### `scrollEdgeAppearance`

Controls the appearance settings when the scrollable content reaches the matching edge of the navigation bar.

| Type                                                       | Required | Platform |
| ---------------------------------------------------------- | -------- | -------- |
| [Scroll Edge Background](options-scrollEdgeAppearance.mdx) | No       | iOS 13+  |

### `barStyle`

Control the TopBar blur style. Requires `translucent: true`.

| Type                    | Required | Platform |
| ----------------------- | -------- | -------- |
| enum('default','black') | No       | iOS      |

### `height`

Set TopBar height, in dp units, on Android only. For iOS use `largeTitle` see [Options](options-largeTitle.mdx).

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `borderColor`

Change the topBar border color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `borderHeight`

Set the border height of the navbar in dp.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `drawBehind`

Controls if child should be drawn behind the TopBar or below it.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `elevation`

Set the elevation of the TopBar in dp. This option changes how the shadow under the TopBar looks. Setting this value to 0 will remove the shadow completely.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `hideOnScroll`

Hide the TopBar when a scrolling layout is scrolled.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

:::warning Deprecation warning
This option is currently deprecated and will be removed in a future release. Please use the [OptionsSearchBar](topBar-searchBar.mdx) option instead.
:::

### `hideNavBarOnFocusSearchBar`

Indicates whether the navigation bar should be hidden when searching. True by default.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS 11+  |

### `leftButtons`

An array of buttons to be displayed at the right-side of the TopBar. Button layout is from left to right. See the [Buttons](options-button) section for more details.

:::info Android support
Android currently only supports a single left button and does not support custom left Buttons.
:::

| Type                           | Required | Platform |
| ------------------------------ | -------- | -------- |
| [[Button]](options-button.mdx) | No       | Both     |

### `leftButtonColor`

Default color for left buttons.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `noBorder`

Disables border at the bottom of the TopBar.
:::important
For disabling the border completely, you also need to disable [scrollEdgeAppearance.noBorder](options-scrollEdgeAppearance#noborder)
:::

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `rightButtons`

An array of buttons to be displayed at the right side of the TopBar. Button layout is from right to left. See the [Buttons](options-button) section for more details.

| Type                           | Required | Platform |
| ------------------------------ | -------- | -------- |
| [[Button]](options-button.mdx) | No       | Both     |

### `rightButtonColor`

Default color for the right button.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `searchBar`

Controls the SearchBar.

| Type                                     | Required | Platform |
| ---------------------------------------- | -------- | -------- |
| [OptionsSearchBar](topBar-searchBar.mdx) | No       | iOS 11+  |

:::warning Deprecation warning
This option is currently deprecated and will be removed in a future release. Please use the [OptionsSearchBar](topBar-searchBar.mdx) option instead.
:::

### `searchBarHiddenWhenScrolling`

Hides the UISearchBar when scrolling.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS 11+  |

:::warning Deprecation warning
This option is currently deprecated and will be removed in a future release. Please use the [OptionsSearchBar](topBar-searchBar.mdx) option instead.
:::

### `searchBarPlaceholder`

The placeholder value in the UISearchBar.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | iOS 11+  |

:::warning Deprecation warning
This option is currently deprecated and will be removed in a future release. Please use the [OptionsSearchBar](topBar-searchBar.mdx) option instead.
:::

### `searchBarBackgroundColor`

The background color of the UISearchBar's TextField.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | iOS 13+  |

:::warning Deprecation warning
This option is currently deprecated and will be removed in a future release. Please use the [OptionsSearchBar](topBar-searchBar.mdx) option instead.
:::

### `searchBarTintColor`

The tint color of the UISearchBar. Affects text selection color, as well as "Cancel" button color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | iOS 13+  |

---

### Api Options StatusBar (`website/docs/api/options-statusBar.mdx`)

---
id: options-statusBar
title: Status Bar Options
sidebar_label: Status Bar
---

```js
const options = {
  statusBar: {},
};
```

### `visible`

Set the status bar visibility.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

### `style`

Set the text color of the status bar.

| Type                  | Required | Platform | Default |
| --------------------- | -------- | -------- | ------- |
| enum('light', 'dark') | No       | Both     | 'light' |

### `backgroundColor`

Set the background color of the status bar.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Android  |

### `drawBehind`

Draw screen behind the status bar.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

### `translucent`

Set the status bar to be translucent.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Android  |

### `animate`

Animate StatusBar style changes.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `blur`

Blur content beneath the StatusBar.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

### `hideWithTopBar`

Automatically hide the StatusBar when the TopBar hides.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | iOS      |

---

### Api Options Subtitle (`website/docs/api/options-subtitle.mdx`)

---
id: options-subtitle
title: Subtitle Options
sidebar_label: Subtitle
---

Controls the top bar subtitle.

```js
const options = {
  topBar: {
    subtitle: {},
  },
};
```

### `text`

Subtitle text.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `fontSize`

Subtitle fontSize. On Android this value is `sp`.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `color`

Subtitle color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `fontFamily`

Subtitle FontFamily.

| Type       | Required | Platform |
| ---------- | -------- | -------- |
| FontFamily | No       | Both     |

### `fontStyle`

| Type                     | Required | Platform |
| ------------------------ | -------- | -------- |
| enum('normal', 'italic') | No       | Both     |

### `fontWeight`

| Type                                                                                  | Required | Platform |
| ------------------------------------------------------------------------------------- | -------- | -------- |
| enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') | No       | Both     |

### `alignment`

`fill` will make the subtitle stretch and consume all available space in the TopBar while `center` will center the subtitle in the middle of the TopBar.

| Type                   | Required | Platform |
| ---------------------- | -------- | -------- |
| enum('center', 'fill') | No       | Both     |

### `testID`

Used to interact with the TopBar in e2e tests.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

---

### Api Options Title (`website/docs/api/options-title.mdx`)

---
id: options-title
title: Title Options
sidebar_label: Title
---

Controls the top bar title.

```js
const options = {
  topBar: {
    title: {},
  },
};
```

### `text`

Set the title for the TopBar.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| string | No       | Both     |

### `fontSize`

Set the title font size. On Android this value is in `sp`.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Both     |

### `color`

Set the title color.

| Type  | Required | Platform |
| ----- | -------- | -------- |
| Color | No       | Both     |

### `fontFamily`

Set the title font family.

| Type       | Required | Platform |
| ---------- | -------- | -------- |
| FontFamily | No       | Both     |

### `fontStyle`

| Type                     | Required | Platform |
| ------------------------ | -------- | -------- |
| enum('normal', 'italic') | No       | Both     |

### `fontWeight`

| Type                                                                                  | Required | Platform |
| ------------------------------------------------------------------------------------- | -------- | -------- |
| enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') | No       | Both     |

### `alignment`

`fill` will make the title stretch and consume all available space in the TopBar while `center` will center the title in the middle of the TopBar.

:::info defaults
`center` is the default option on iOS while `fill` is the default for Android.
:::

| Type                  | Required | Platform |
| --------------------- | -------- | -------- |
| enum('center','fill') | No       | Both     |

### `component`

Set a react [component](layout-component.mdx) as the title. If this option is specified then text is ignored.

| Type                              | Required | Platform |
| --------------------------------- | -------- | -------- |
| [Component](layout-component.mdx) | No       | Both     |

### `topMargin`

Change to TopBar's top margin.

| Type   | Required | Platform |
| ------ | -------- | -------- |
| number | No       | Android  |

### `visible`

Determines whether the TopBar is visible or not.

| Type    | Required | Platform |
| ------- | -------- | -------- |
| boolean | No       | Both     |

---

### Api TopBar SearchBar (`website/docs/api/topBar-searchBar.mdx`)

---
id: topBar-searchBar
title: SearchBar
sidebar_label: Layout
---

## `visible`

| Type   | Required | Platform | Description                                                                                                                                                    |
| ------ | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| boolean | No      | iOS | Determines if SearchBar is visible or not |

## `focus`

| Type   | Required | Platform | Description                                                                                                                                                    |
| ------ | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| boolean | No      | iOS | Auto focuses search bar |


## `hideOnScroll`

| Type                    | Required | Platform | Description                    |
| ----------------------- | -------- | -------- | ------------------------------ |
| boolean | No       | iOS | Hides the UISearchBar when scrolling. |

## `hideTopBarOnFocus`

| Type               | Required | Platform | Description                   |
| ------------------ | -------- | -------- | ----------------------------- |
| boolean | No      | iOS | Indicates whether the navigation bar should be hidden when searching. True by default. |

## `obscuresBackgroundDuringPresentation`

| Type                    | Required | Platform | Description                    |
| ----------------------- | -------- | -------- | ------------------------------ |
| boolean | No       | iOS | A Boolean indicating whether the underlying content is obscured during a search. |

## `backgroundColor`

| Type                    | Required | Platform | Description                    |
| ----------------------- | -------- | -------- | ------------------------------ |
| Color | No       | iOS | The background color of the UISearchBar's TextField. |

## `tintColor`

| Type                    | Required | Platform | Description                    |
| ----------------------- | -------- | -------- | ------------------------------ |
| Color | No       | iOS | The tint color of the UISearchBar. Affects text selection color, as well as "Cancel" button color. |

## `searchBarPlaceholder`

| Type                    | Required | Platform | Description                    |
| ----------------------- | -------- | -------- | ------------------------------ |
| string | No       | iOS | The placeholder value in the UISearchBar. |

## `cancelText`

| Type                    | Required | Platform | Description                                           |
| ----------------------- | -------- | -------- | ----------------------------------------------------- |
| string                  | No       | iOS      | The text value of "Cancel" button in the UISearchBar. |

## `placement`

| Type                    | Required | Platform | Description                                                                             |
| ----------------------- | -------- | -------- | --------------------------------------------------------------------------------------- |
| string                  | No       | iOS 26   | 'stacked' (default) or 'integrated' where 'integrated' is the new iOS 26 look and feel. |

---

### Docs Community Libraries (`website/docs/docs/community-libraries.mdx`)

---
id: community-libraries
title: Community libraries
sidebar_label: Community libraries
---

React Native Navigation has an active community with a bunch of support libraries.

## Utilities

[React Native Navigation Hooks](https://github.com/underscopeio/react-native-navigation-hooks) :
A set of React hooks for React Native Navigation.

[React Native Navigation Register Screens](https://github.com/karlmarxlopez/react-native-navigation-register-screens) : 
Utility function to register array of screens instead of calling `Navigation.registerComponent` multiple times.

## Extensions

[React Native Navigation Drawer Extension](https://github.com/lukebrandonfarrell/react-native-navigation-drawer-extension) :
Drawer API built on top of React Native Navigation for iOS and Android. 

[React Native Navigation Search Bar](https://github.com/lukebrandonfarrell/react-native-navigation-search-bar) :
React Native Elements search bar with collapsible header built for React Native Navigation.

[React Native Navigation Bottom Sheet Extension](https://github.com/CursedWizard/react-native-navigation-bottom-sheet) :
A performant customizable bottom sheet component built on top of React Native Navigation.

---

### Docs Docs Installing (`website/docs/docs/docs-Installing.mdx`)

---
id: installing
title: Installation
sidebar_label: Installation
---

## Requirements

- node ≥ 18.18
- react-native ≥ 0.77
- new architecture enabled

## npm or yarn

npm:

```sh
npm install --save react-native-navigation
```

yarn:

```sh
yarn add react-native-navigation
```

## Installing with `npx rnn-link` (automatic installation)

You can benefit from autolinking for some of the necessary installation steps. But unlike most other libraries, react-native-navigation requires you to make a few changes to native files.

We've simplified the process through a set of scripts. So to make all the necessary changes automatically, in your project's root folder run:

```sh
npx rnn-link
````

Make sure to commit the changes introduced by the `rnn-link` script.

> The automatic linking is optimized for new applications created via the `npx @react-native-community/cli@latest init` command. If you are migrating from a version of react-native-navigation older than v7, it's recommended to check the steps manually after the script runs.

> In iOS, from React-native 0.79 onwards the rnn-link will make the necessary changes only to the AppDelegate.swift file. The Objective-C version of the AppDelegate will need to be changed manually (see below).

If one of the steps failed or you can't run (or are not comfortable with) the automatic scripts, you'll need to complete the relevant steps in the manual installation steps below, for both platforms.


### CocoaPods

After the the automatic scripts completed successfully, run pod install:

```sh
pod install --project-directory=ios
```

### Update index.js file

`index.js` is typically used as an entry point into the app. It's first parsed and executed by the JS engine, therefore we'll want to show our UI from there.

The following diff demonstrates changes needed to be made to `index.js`, initialized by `react-native init`.

```diff
+import { Navigation } from "react-native-navigation";
-import {AppRegistry} from 'react-native';
import App from "./App";
-import {name as appName} from './app.json';

-AppRegistry.registerComponent(appName, () => App);
+Navigation.registerComponent('com.myApp.WelcomeScreen', () => App);

+Navigation.events().registerAppLaunchedListener(() => {
+   Navigation.setRoot({
+     root: {
+       stack: {
+         children: [
+           {
+             component: {
+               name: 'com.myApp.WelcomeScreen'
+             }
+           }
+         ]
+       }
+     }
+  });
+});
```

### Finish

If you followed the steps successfully up to this point, then rebuild your application and you are good to go:

```sh
react-native run-ios
react-native run-android
```

:::tip
This is a good moment to build your application in both platforms, validate that everything is working properly and commit your changes. If you're coming from a fresh `npx @react-native-community/cli@latest init` project, then you should be seeing the Welcome screen as usual, but under the hood your application is using react-native-navigation!
::::

---

## Manual Installation

If installation with `npx rnn-link` did not work, follow the manual installation steps below.

### iOS

> Make sure your Xcode is updated. We recommend editing `.h`, `.mm` and `.swift` files in Xcode as the IDE will usually point out common errors.

#### Installation with CocoaPods

```sh
cd ios && pod install
```

#### Native Installation

> **Choose your implementation language**: Depending on whether your project uses Swift or Objective-C, follow the appropriate section below. Most new React Native projects use Swift by default.

### React-Native 0.77 - 0.78:
##### For Swift projects

In Xcode, you will need to update this file: `AppDelegate.swift`

```diff
import UIKit
import React
- import React_RCTAppDelegate
+ import ReactNativeNavigation
import ReactAppDependencyProvider

@main
- class AppDelegate: RCTAppDelegate {
+ class AppDelegate: RNNAppDelegate {
...
```

##### For Objective-C projects

In Xcode, you will need to edit this file: `AppDelegate.h`. Its content should look like this:

```diff
#import <UIKit/UIKit.h>
- #import <RCTAppDelegate.h>
+ #import "RNNAppDelegate.h"

- @interface AppDelegate : RCTAppDelegate
+ @interface AppDelegate : RNNAppDelegate

@end

```

### React-Native 0.79:

##### For Swift projects

```diff
-import React_RCTAppDelegate
+import ReactNativeNavigation

-class AppDelegate: UIResponder, UIApplicationDelegate {
+class AppDelegate: RNNAppDelegate {

-func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
+override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
+self.reactNativeDelegate = ReactNativeDelegate()
+super.application(application, didFinishLaunchingWithOptions: launchOptions)

-let delegate = ReactNativeDelegate()
-let factory = RCTReactNativeFactory(delegate: delegate)
-delegate.dependencyProvider = RCTAppDependencyProvider()

-reactNativeDelegate = delegate
-reactNativeFactory = factory

-window = UIWindow(frame: UIScreen.main.bounds)

-factory.startReactNative(
-  withModuleName: "RN79",
-  in: window,
-  launchOptions: launchOptions
-)
```

##### For Objective-C projects

In Xcode, you will need to edit this file: `AppDelegate.h`. Its content should look like this:

```diff
-@interface AppDelegate: UIResponder, UIApplicationDelegate
+@interface AppDelegate : RNNAppDelegate

-@property (nonatomic, strong) UIWindow *window;
-@property (nonatomic, strong) ReactNativeDelegate *reactNativeDelegate;
-@property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory;
```

`AppDelegate.m`
```diff
-  ReactNativeDelegate *delegate = [[ReactNativeDelegate alloc] init];
-  RCTReactNativeFactory *factory = [[RCTReactNativeFactory alloc] initWithDelegate:delegate];
-  delegate.dependencyProvider = [[RCTAppDependencyProvider alloc] init];

-  self.reactNativeDelegate = delegate;
-  self.reactNativeFactory = factory;
-  self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];

-  [factory startReactNativeWithModuleName:@"RN79"
-                                      in:self.window
-                            launchOptions:launchOptions];
+  self.reactNativeDelegate = [ReactNativeDelegate new];
+  [super application:application didFinishLaunchingWithOptions:launchOptions];
```

### Firebase integration on React-Native 0.79:

For Firebase integration with static frameworks the following change needs to be added to your `podfile`:

`podfile`
```diff
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

+ static_frameworks = [
+  'FirebaseCore',
+  'FirebaseCoreExtension',
+  'GoogleUtilities',
+  'FirebaseCoreInternal',
+  'FirebaseInstallations',
+  'GoogleDataTransport',
+  'FirebaseFirestoreInternal',
+  'FirebaseMessagingInternal',
+  'FirebaseAuth',
+ ]

+ pre_install do |installer|
+  installer.pod_targets.each do |pod|
+    if static_frameworks.include?(pod.name)
+      puts "Configuring #{pod.name} as static framework"
+      def pod.build_type
+        Pod::BuildType.new(:linkage => :static, :packaging => :framework)
+      end
+    end
+  end
+ end

target <ProjectName> do
  config = use_native_modules!

+ $RNFirebaseAsStaticFramework = true

+  pod 'FirebaseAuthInterop', :modular_headers => true
+  pod 'FirebaseAppCheckInterop', :modular_headers => true
+  pod 'RecaptchaInterop', :modular_headers => true
...
```

### Android

> Make sure your Android Studio installation is up to date. We recommend editing `gradle` and `kotlin` files in Android Studio as the IDE will suggest fixes and point out errors, this way you avoid most common pitfalls.

#### 1. Update `android/build.gradle`:

```diff
buildscript {
    ext {
        kotlinVersion = "2.0.21"
+        RNNKotlinVersion = kotlinVersion
        compileSdkVersion = 35
        buildToolsVersion = "35.0.0"
        minSdkVersion = 24
        targetSdkVersion = 34
        ndkVersion = "27.1.12297006"
    }
  repositories {
        google()
        mavenCentral()
  }
  dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
        classpath("com.facebook.react:react-native-gradle-plugin")
        classpath 'com.android.tools.build:gradle'
  }
}

allprojects {
  repositories {
   google()
    maven {
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
      url "$rootDir/../node_modules/react-native/android"
    }
  }
}
```

#### 2. Update `MainActivity.kt`


```diff
-import com.facebook.react.ReactActivity
+import com.reactnativenavigation.NavigationActivity

-class MainActivity : ReactActivity() {
-    override fun getMainComponentName(): String {
-        return "yourproject"
-    }
-}
+class MainActivity : NavigationActivity()
```

If you have any **react-native** related methods, you can safely delete them.

#### 3. Update `MainApplication.kt`

This file is located in `android/app/src/main/java/com/<yourproject>/MainApplication.java`.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### App root

Now that you're done, don't forget to update the `index.js` file, as [shown above](#update-indexjs-file).

## Troubleshooting

### Build app with gradle command

**prefered solution** - The RNN flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .

```
"scripts": {
  // ...
  "android": "cd ./android && ./gradlew app:assembleDebug && ./gradlew installDebug"
}
```

Now run `npm run android` to build your application

### Force the same support library version across all dependencies

Some of your dependencies might require a different version of one of Google's support library packages. This results in compilation errors similar to this:

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:preDebugBuild'.
> Android dependency 'com.android.support:design' has different version for the compile (25.4.0) and runtime (26.1.0) classpath. You should manually set the same version via DependencyResolution
```

To resolve these conflicts, add the following to your `app/build.gradle`:

```groovy
android {
    ...
}

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support' && requested.name != 'multidex') {
            details.useVersion "${rootProject.ext.supportLibVersion}"
        }
    }
}

dependencies {
    ...
    implementation 'com.android.support:design:25.4.0'
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
}

```

---

### Docs Docs Advanced Navigation (`website/docs/docs/docs-advanced-navigation.mdx`)

---
id: advanced-navigation
title: Advanced navigation
sidebar_label: Advanced navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

## Tab navigation

As mobile applications become bigger and more complex, they usually end up containing multiple primary high-level destinations, which are logically independent from one another. The `BottomTabs` layout is often used when an app contains three to five top-level destinations which should be accessible from anywhere in the app.

Lets return to the example code from the previous section ([Basic navigation](basic-navigation)) and see how we can convert it to a tab-based application. We'll use the BottomTabs layout to display tabs at the bottom of the screen. Similarly to `Stack` layout, The BottomTabs layout also contains a `children` property where each child will be displayed in a tab.

Lets change our code to the following and reload the app.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Now our app has two tabs at the bottom of the screen and our users can easily navigate between them.

<img width="40%" src={useBaseUrl('img/stack4.png')} />

## Replacing the root

Up until now, we've discussed how to navigate within the same layout structure. We'll now learn how to replace the entire layout structure to display a new Root. A real life example for this use case would be, for instance, if you need to switch from a login screen to the app's main root. Replacing the root fits this use case since we'd like to discard the previous root (login root) entirely when switching to the main root.

To demonstrate this, we'll make the following changes to our code:

1. Add a login screen with a login button.
2. When the button is clicked, we will switch to the main root.
3. Replace our current root with the login screen. We'll also extract both roots to variables to improve code readability.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Conditional roots

Now that our initial root is the Login root, we're facing a new problem - how do we show the Login root only to users that are not logged in? Since our initial root is determined in the `registerAppLaunchedListener` callback, we'll check if a user is logged in there and set the appropriate root accordingly.

```jsx
Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot(isLoggedIn() ? mainRoot : loginRoot);
});

function isLoggedIn() {
  // TODO: your business logic goes here
}
```

---

### Docs Docs App Launch (`website/docs/docs/docs-app-launch.mdx`)

---
id: app-launch
title: Launching the app
sidebar_label: Launching the app
---

When your app is launched for the first time, the bundle is parsed and executed. At this point you need to display your UI. To do so, listen to the `appLaunched` event and call `Navigation.setRoot` when that event is received.

```js
Navigation.events().registerAppLaunchedListener(() => {
  // Each time the event is received you should call Navigation.setRoot
});
```

:::important
Register the app launched listener as soon as possible - this should be one of the first lines in your `index.js` file.
:::

If you're observing a "white screen" or a hanging splash screen after relaunching your app, it probably means `Navigation.setRoot` isn't called as soon as the app is launched. Perhaps the listener was registered too late.

## Difference between the platforms
When your app is launched, RN makes sure JS context (which is what enables you to execute JavaScript code) is running. There are quite a few differences between iOS and Android in this regard.

### iOS
Whenever an app is put into the background, the app process can potentially be destroyed by the system. If this destruction takes place, the JS context will be destroyed alongside with the app process.

### Android
An Android application is typically bound to two contexts:

1. Application context - bound to the app process
1. Activity context - bound to app UI

React's JS Context is executed on and bound to the Application context. This means that even when the Activity context (and thus the UI) is destroyed, React's JS Context remains active until the Application (and your process) are destroyed by the system.

:::caution
Because of this, when your app returns to foreground, JS Context might still exist on Android, even when the Activity and UI contexts have been destroyed - meaning you might not need to initialise all of your app logic; instead, you'll only need to call `Navigation.setRoot` to repopulate the UI context. This circumstance can easily be determined by setting a flag on your app's first `appLaunched` event, and checking the value of that flag on subsequent `appLaunched` events -- if the flag is true in your `appLaunched` callback, you need to call `Navigation.setRoot` to repopulate the UI.
:::

---

### Docs Docs Basic Navigation (`website/docs/docs/docs-basic-navigation.mdx`)

---
id: basic-navigation
title: Basic navigation
sidebar_label: Basic navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

Generally, any mobile app consists of various destinations which display some content to the user. And in vast majority of cases using an app means navigating between these destinations. React-native-navigation provides ways for you to layout your content on user screen in a logical and performant manner.

React Native Navigation's stack layout lets you push screens, and also navigate back to previous screens. Screens pushed into the stack hide the previous screen in the stack, making the user focus on a single screen at a time. Let's look at a stack layout that provides basic navigation for an app.

## Creating a stack

```jsx
// In index.js of a new project
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { Navigation } from 'react-native-navigation';

const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Home Screen</Text>
    </View>
  );
};
Navigation.registerComponent('Home', () => HomeScreen);

Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot({
    root: {
      stack: {
        children: [
          {
            component: {
              name: 'Home'
            }
          }
        ]
      }
    }
  });
});

const styles = StyleSheet.create({
  root: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'whitesmoke'
  }
});
```

Running this code will render a screen with an empty TopBar and your HomeScreen component (shown below). The TopBar is part of the stack layout, we'll work on configuring it later.

<img width="40%" src={useBaseUrl('img/stack1.png')} />

## Specifying options

You can specify options of each layout (Stack, component pushed into a stack, etc.) to configure various parameters like the TopBar title or color. Lets spice things up by changing the TopBar color and while we're at it, also move the title to the TopBar.

Lets change the Home screen declaration to the following and reload the app to see the changes.
```jsx
const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Hello React Native Navigation 👋</Text>
    </View>
  );
};
HomeScreen.options = {
  topBar: {
    title: {
      text: 'Home',
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
}
```

Our app should now look like this:
<img width="40%" src={useBaseUrl('img/stackOptions.png')} />

## Navigating in a stack

In the previous section we created a stack and initialized it with a single child. We'll now learn how to add another child to the stack. From now on, we'll call the action of adding children to the stack 'push', and removing children - 'pop'.

In order to push another screen to the stack, we will add a button to the home screen and call `Navigation.push`. The 'push' command accepts two parameters, the first is the id used to indicate into which stack to push the screen and the second is the screen we're pushing. After pushing a screen, a back button is added automatically to the TopBar so the users can navigate easily back to the previous screen.

You can read more about the stack layout [here](docs-stack.mdx) or dive right into the API [here](../api/layout-stack).

:::info componentId
Each React component registered with `Navigation.registerComponent` is assigned a unique `componentId` by Navigation. This unique id is used with Navigation commands (like the push command) to indicate into which stack we'd like to push. In this case, by using the componentId of the Home screen, we are telling Navigation to push into the stack containing the Home screen.
:::

```js
Navigation.push(props.componentId, {
  component: {
    name: 'Settings', // Push the screen registered with the 'Settings' key
    options: { // Optional options object to configure the screen
      topBar: {
        title: {
          text: 'Settings' // Set the TopBar title of the new Screen
        }
      }
    }
  }
});
```

Lets change our code to the following snippet below and reload the app. Now our Home should contain a button which when pressed, pushes a new screen into the stack. We've successfully navigated to a new screen! 👏

```
/* Detailed source-code truncated for AI context efficiency. */
```

<img width="40%" src={useBaseUrl('img/stack2.gif')} />

## App theme

Our app is growing and already contains two screens. This introduces a new problem - while the home screen has a nice purple TopBar, our settings screen seems pretty dull as it still uses the default system look and feel.

Currently, our style declaration applies only to the Home screen, so lets apply it to all of our screens by using `Navigation.setDefaultOptions`.

```js
Navigation.setDefaultOptions({
  statusBar: {
    backgroundColor: '#4d089a'
  },
  topBar: {
    title: {
      color: 'white'
    },
    backButton: {
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
});
```

We need to add this snippet before registering the `registerAppLaunchedListener`. This way we ensure our theme is applied when our root is set. Our code should now look like this:

```
/* Detailed source-code truncated for AI context efficiency. */
```

Lets run our code again - now our design is consistent across both screens.

<img width="40%" src={useBaseUrl('img/stack3.gif')} />

## Summary

We've learned the basics of navigation with React Native Navigation by implementing a stack and pushing screens into it.
We've also learned a few methods of applying styles to our screens and layouts with the Options mechanism.

* Navigation.setRoot() sets the root layout of our app. The initial root has to be set from an `AppLaunchedEvent` callback.
* Options can be applied directly to components.
* Screens can be added to a stack with the `Navigation.push()` command.
* Components registered with `Navigation.registerComponent()` are injected with a `componentId` which is used when navigating.
* Themes are applied via the `Navigation.setDefaultOptions()` command.

In the next section we'll explore a more advance navigation patterns using BottomTabs layout and also see how, and why, multiple roots are set.

---

### Docs Docs Before You Start (`website/docs/docs/docs-before-you-start.mdx`)

---
id: before-you-start
title: Before you start
sidebar_label: Before you start
---

React Native Navigation is a module, dependent on and intended to be used alongside [React Native](https://github.com/facebook/react-native), so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their [getting started](https://reactnative.dev/docs/getting-started) tutorial, and then come back here when you're ready.

We also assume you are working on a Mac with XCode and Android Studio installed and setup. You can also make it work in a Linux distribution, of course, but in that case bear in mind that some sections of the docs that deal with iOS might not be relevant to you.

If you want to dig right into it, start with [installing](docs-Installing.mdx) the library. If you're just looking around, we suggest checking out [basic navigation](docs-basic-navigation.mdx) first.

---

### Docs Docs BottomTabs (`website/docs/docs/docs-bottomTabs.mdx`)

---
id: bottomTabs
title: Bottom tabs
sidebar_label: Bottom tabs
---
import useBaseUrl from '@docusaurus/useBaseUrl';

Bottom tabs refers to a row of links, displayed at the bottom of the screen, and is referred to as "Tab Bar" in iOS and as "Bottom Navigation Bar" on Android. Usually these are intended to be used to switch between top-level content views with a single tap.

## Creating bottom tabs

BottomTabs provide flat navigation and access to up to five equally important top-level root destinations. While any type of layout can be displayed in a tab, typically, [Stacks](stack) are used, since they allow for vertical navigation within a tab.

### Example
Lets see how to create a simple BottomTabs layout. There are a few things to notice here:
1. Each child represents a tab on the screen.
2. The root layout for each tab is a stack to allow for vertical navigation within the tab.
3. Each stack declares `bottomTab` options which are used to configure the tab's text, icon, color etc.

```js
bottomTabs: {
  id: 'BOTTOM_TABS_LAYOUT',
  children: [
    {
      stack: {
        id: 'HOME_TAB',
        children: [
          {
            component: {
              id: 'HOME_SCREEN',
              name: 'HomeScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./home.png')
          }
        }
      }
    },
    {
      stack: {
        id: 'PROFILE_TAB',
        children: [
          {
            component: {
              id: 'PROFILE_SCREEN',
              name: 'ProfileScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./profile.png')
          }
        }
      }
    }
  ]
}
```

Once we run this code, our BottomTabs should look like this:
<img width="40%" src={useBaseUrl('img/bottomTabs.png')} />

## Selecting Tabs Programmatically
Tabs can be selected programmatically by updating the `currentTabIndex` or `currentTabId` options.

We'll use the BottomTabs layout showcased [above](bottomTabs#example) to demonstrate programmatic tab selection.

### Selecting a tab by index
The following mergeOptions command will select the second tab. We're passing the id of our BottomTabs layout, but we could also use the id of any of the child components, for example `PROFILE_TAB` or `PROFILE_SCREEN`.

```js
Navigation.mergeOptions('BOTTOM_TABS_LAYOUT', {
  bottomTabs: {
    currentTabIndex: 1
  }
});
```

### Selecting a tab by id
Tabs can also be selected by id (`componentId`). This is particularly useful in cases where you don't know in which tab a screen is contained.
For example, if invoked from one of the child components, `HOME_SCREEN` or `SETTINGS_SCREEN`, the following merge command will select the tab containing the child.

```js
Navigation.mergeOptions(this.props.componentId, {
  bottomTabs: {
    currentTabId: this.props.componentId
  }
});
```

## Changing BottomTabs visibility

The `visible` property is used to control the BottomTab visibility. Visibility can be toggled dynamically using the `mergeOptions` command.
```js
Navigation.mergeOptions(componentId, {
  bottomTabs: {
    visible: false
  },
});
```

Visibility can also be changed when pushing screens.
```js
Navigation.push(componentId, {
  component: {
    name: 'pushedScreen',
    options: {
      bottomTabs: {
        visible: false
      }
    }
  }
});
```

## Updating tab options dynamically

To update a tab option, like an icon, text or color, simply call `mergeOptions` with new options using the id of a component or layout contained in the tab you wish to update.

For instance, in the example below we update the color of a specific tab:
```js
Navigation.mergeOptions(componentId, {
  bottomTab: {
    iconColor: 'red',
    textColor: 'red'
  },
});
```

## Styling the tabs

The bottom-tabs feature support for an enhanced, floating-like layout that offers a modern and visually appealing alternative to the default design.
This layout creates the illusion of the tabs hovering above the screen content, adding depth and sophistication to the user interface.

To achieve this effect (and fully customize it), you can use the following bottom-tabs styling options:

```javascript
Navigation.setRoot({ // An example; push() also support this
  root: {
    bottomTabs: {
      options: {
        layoutStyle: 'compact',
        translucent: true,
        drawBehind: true,
        bottomMargin: 15,

        // Cosmetics:
        cornerRadius: 15,
        blurRadius: 2.0, // Actual radius would be 2.0 * 4 = 8.0
        backgroundColor: 'rgba(50, 50, 50, 0.4)', // A subtle semi-transparent (40%) hue
        elevation: 1, // Soft surrounding shadow effect (i.e. the elevation)
      },
      children: [
        // ...
      ],
    },
  },
});
```

* Setting `layoutStyle: compact` keeps the tabs container from taking up the entire screen width, thus leaving room for the screen content to appear on both its sides.
* The `translucent` property adds a semi-transparent background, while `drawBehind` and `bottomMargin` allow the screen content to flow beneath the hovering tabs.
* The `cornerRadius` rounds the edges of the tabs, giving them a soft, card-like appearance.

> Note: Settings some of the options via `mergeOptions` is discouraged, as they'd only apply for the currently visible tab.

## Custom React tab items

To render arbitrary React components as tab items (Lottie, SVG, custom badges, full custom bar design), use `bottomTab.component` on **every** tab and optionally `bottomTabs.customRow` for the floating row chrome.

See the [Custom bottom tabs](customBottomTabs) guide for setup, props, platform differences, and examples.

## Controlling tab loading

By default, all tabs are mounted at the same time. This can have a negative impact on performance since screens which are not visible to the user are mounted.

The order in which tabs are mounted can be configured with the `tabsAttachMode` option:

* `together` - all tabs are mounted at the same time, this is the default behavior.
* `afterInitialTab` - after initial tab is mounted, other tabs are mounted.
* `onSwitchToTab` - initial tab is mounted, other tabs are mounted when the user navigates to them for the first time.

---

### Docs Docs CustomBackNavigation (`website/docs/docs/docs-customBackNavigation.mdx`)

---
id: customBackNavigation
title: Custom back navigation
sidebar_label: Custom back navigation
---

Back navigation lets users move backwards through the screens they previously visited.

The most common form of back navigation is done through the **back button**. The [stack](stack) layout contains a back button by default, also known as the _software back button_.

RNN handles the back navigation for you, but there are use cases where you might need to override the default behavior of the back navigation. For example, when editing a blog post, you might want to prompt the user about unsaved changes instead of navigating to the previous destination.

### Additional back navigation methods

- Android devices include a _hardware back button_, located at the bottom of the device.
- Android 11 introduced an opt-in gesture navigation system that hides the [NavigationBar](../api/options-navigationBar). When enabled, the hardware back button is replaced with a back gesture performed with a horizontal swipe across the screen.
- The stack layout on iOS supports a back gesture by default. Like the android back gesture, it's performed by swiping across the screen.

## Handling the software back button

The software back button is located in the TopBar and is responsible for popping the top most screen in the stack. It's configured in the [TopBar](../api/options-stack) options.

To handle the software back button, we must first disable the default behavior which is to pop the top most screen:

```js
options: {
  topBar: {
    backButton: {
      popStackOnPress: false;
    }
  }
}
```

Now, when the software back button is pressed, instead of popping the screen RNN will emit a [navigationButtonPress](../api/events/#navigationbuttonpressed-event) event which can be handled in JS.

```js
navigationButtonPressed({ buttonId }) {
  if (buttonId === 'RNN.back') {
    console.log('The software back button was pressed!');
  }
}
```

## Handling the hardware back button

Unlike the software back button which affects the stack it's part of, the hardware back button isn't bound to a specific layout. Instead, The hardware back button affects the top most layout that responds to back navigation.

When a stack containing more than one child is focused, pressing the hardware back button will pop the stack. When a modal is displayed and the current stack has exactly one child, pressing the hardware back button will dismiss the modal.

To handle the hardware back button, we must first disable the default behavior for the desired action (pop stack or dismiss modal) through options:

```js
options: {
  hardwareBackButton: {
    dismissModalOnPress: false,
    popStackOnPress: false,
  }
}
```

Once the default behaviors are disabled, RNN will emit a [navigationButtonPress](../api/events/#navigationbuttonpressed-event) with the `RNN.hardwareBackButton` id.

```js
navigationButtonPressed({ buttonId }) {
  if (buttonId === 'RNN.hardwareBackButton') {
    console.log('The hardware back button was pressed!');
  }
}
```

:::info Note
The hardware back button is available on Android only.
:::

:::info Note 2
When gesture navigation is enabled on Android, the back gesture is handled as a hardware back press.
:::

## Disabling the iOS pop gesture

The iOS stack layout can be popped with a swipe gesture. If desired, the swipe gesture can be disabled via options:

```js
options: {
  popGesture: false;
}
```

---

### Docs Docs CustomBottomTabs (`website/docs/docs/docs-customBottomTabs.mdx`)

---
id: customBottomTabs
title: Custom bottom tab items
sidebar_label: Custom bottom tabs
---

Custom bottom tabs let you render a **React component** for each tab item instead of the built-in icon + label. Use this when you need Lottie animations, SVG icons, custom badge layouts, or a fully custom tab bar design.

The same JavaScript API works on **iOS and Android**. Both platforms use a floating custom row when every tab declares `bottomTab.component`.

## Requirements

1. **Every tab** in a `bottomTabs` layout must set `bottomTab.component`. If only some tabs use a custom component, RNN logs a warning and falls back to native rendering for **all** tabs in that bar.
2. Register your tab item component with `Navigation.registerComponent` (same as any other screen).
3. Optionally set `bottomTabs.customRow` on the layout to style the floating row chrome (margins, height, background, corner radius).

## Basic example

```js
// 1. Register the tab item component (e.g. in index.js)
Navigation.registerComponent('MyTabItem', () => require('./MyTabItem'));

// 2. Use it on every tab
Navigation.setRoot({
  root: {
    bottomTabs: {
      options: {
        bottomTabs: {
          customRow: {
            backgroundEffect: 'glass',
            cornerRadius: 28,
            horizontalMargin: 16,
            bottomMargin: 0,
            height: 67,
          },
        },
      },
      children: [
        {
          stack: {
            children: [{ component: { name: 'HomeScreen' } }],
            options: {
              bottomTab: {
                component: { name: 'MyTabItem' },
                badge: '3',
              },
            },
          },
        },
        {
          stack: {
            children: [{ component: { name: 'SearchScreen' } }],
            options: {
              bottomTab: {
                component: { name: 'MyTabItem' },
              },
            },
          },
        },
        {
          stack: {
            children: [{ component: { name: 'ProfileScreen' } }],
            options: {
              bottomTab: {
                component: { name: 'MyTabItem' },
              },
            },
          },
        },
      ],
    },
  },
});
```

See the playground: **Layouts → BottomTabs Custom Component** (`LayoutsScreen.bottomTabsWithCustomComponent`).

## Tab item component props

RNN creates one React surface per tab and pushes prop updates when selection or badge changes.

| Prop | Type | Description |
| ---- | ---- | ----------- |
| `componentId` | `string` | Stable id for this tab item instance |
| `tabIndex` | `number` | Zero-based index of the tab |
| `selected` | `boolean` | Whether this tab is currently selected |
| `badge` | `string \| null` | Mirrors `bottomTab.badge` |

`passProps` from `bottomTab.component.passProps` are merged at creation time only. Use `tabIndex` inside your component to pick icon/label per tab.

### Example tab item

```js
function MyTabItem({ tabIndex, selected, badge }) {
  const labels = ['Home', 'Search', 'Profile'];
  return (
    <View style={{ alignItems: 'center' }}>
      <MyIcon index={tabIndex} selected={selected} />
      <Text style={{ color: selected ? '#007aff' : '#9aa0a6' }}>
        {labels[tabIndex]}
      </Text>
      {badge ? <Badge>{badge}</Badge> : null}
    </View>
  );
}
```

## What is ignored when `component` is set

For tabs that use `bottomTab.component`, these options are **ignored** for that tab's visual content:

`text`, `icon`, `selectedIcon`, `sfSymbol`, `sfSelectedSymbol`, `iconColor`, `selectedIconColor`, `iconWidth`, `iconHeight`, `iconInsets`, `fontFamily`, `fontWeight`, `fontSize`, `selectedFontSize`, `textColor`, `selectedTextColor`

Native still handles tab selection, visibility, `drawBehind`, animations, and `dotIndicator`. Switch tabs from JS with:

```js
Navigation.mergeOptions('BOTTOM_TABS_LAYOUT_ID', {
  bottomTabs: { currentTabIndex: 1 },
});
```

## Events

Taps on custom tab items use the same native selection pipeline as the built-in tab bar. Use the standard [Navigation events](../api/events) listeners:

| Listener | Custom row |
| -------- | ---------- |
| [`registerBottomTabPressedListener`](../api/events#registerbottomtabpressedlistener) | Yes — every tap (iOS and Android) |
| [`registerBottomTabSelectedListener`](../api/events#registerbottomtabselectedlistener) | Yes — when the selected tab changes |
| [`registerBottomTabLongPressedListener`](../api/events#registerbottomtablongpressedlistener) | **No** |

[`bottomTab.selectTabOnPress`](api/options-bottomTab.mdx#selecttabonpress): when `false`, **pressed** still fires; **selected** does not until you change the tab programmatically (for example via `bottomTabs.currentTabIndex`).

[`bottomTab.popToRoot`](api/options-bottomTab.mdx#poptoroot) and Android hardware-back tab history behave the same as with native tab items.

`registerBottomTabLongPressedListener` is **iOS-only** and is wired to the native `UITabBar` long-press gesture. With custom tabs the native bar is hidden and touches go to the custom row, so this listener does not fire for custom tab items.

## Custom row (`bottomTabs.customRow`)

When all tabs use custom components, RNN replaces the visible tab bar chrome with a **floating row** that hosts your React tab cells. Configure it with `bottomTabs.customRow` on the `bottomTabs` layout options.

```js
bottomTabs: {
  options: {
    bottomTabs: {
      customRow: {
        height: 67,
        backgroundEffect: 'glass', // 'glass' | 'blur' | 'none'
        cornerRadius: 28,
        horizontalMargin: 16,
        bottomMargin: 0,
        // backgroundColor: '#ffffff', // optional; overrides backgroundEffect
      },
    },
  },
  children: [/* ... */],
}
```

Options apply on **`setRoot`**, **`showModal`**, **`mergeOptions`**, and **`setDefaultOptions`** (same as other bottom-tabs options).

### `customRow` fields

| Option | Type | Default (when omitted) | Description |
| ------ | ---- | ---------------------- | ----------- |
| `height` | `number` | Native tab content height (+18 on iOS 26+) | Content height of the row in **points/dp**, excluding safe-area inset |
| `backgroundColor` | color | — | Solid background; overrides `backgroundEffect` |
| `backgroundEffect` | `'glass' \| 'blur' \| 'none'` | `'glass'` on iOS 26+, `'blur'` below | Row background style |
| `cornerRadius` | `number` | `28` on iOS 26+, `0` below | Corner radius of the row background |
| `horizontalMargin` | `number` | `16` on iOS 26+, `0` below | Inset from left/right screen edges |
| `bottomMargin` | `number` | `0` | Gap between row bottom and safe-area bottom |

**Total row height** = `height` + safe-area bottom inset + `bottomMargin` (same formula on both platforms).

## Platform behavior

| Topic | iOS | Android |
| ----- | --- | ------- |
| Custom tab cells | React component in custom floating row | Same |
| Native tab bar visuals | Hidden; blank `UITabBarItem`s keep selection | Native bar hidden (`alpha = 0`); `BottomTabs` still drives selection |
| `backgroundEffect: 'glass'` | `UIGlassEffect` (iOS 26+), blur fallback | Semi-opaque material chrome (no system glass API) |
| `backgroundEffect: 'blur'` | `UIBlurEffect` systemChromeMaterial | Semi-opaque material chrome |
| Row shadow | From glass/blur material | Subtle elevation shadow (~3dp, low alpha) to approximate iOS lift |
| Options delivery | Native options parser | JS forwards `customRow` to `RNNBottomTabsCustomRowModule` before layout commands |
| Min tabs | 2 (UIKit) | 3 (`AHBottomNavigation`) |

### iOS implementation notes

- Custom row: `RNNBottomTabsCustomRow` — hosts cells, applies `customRow` options, handles layout and taps.
- iOS 26+: defaults match the floating tab bar (glass, 28pt radius, 16pt horizontal margin).
- `tabBarMinimizeBehavior` is forced to `never` when custom item views are active.

### Android implementation notes

- Custom row lives in `com.reactnativenavigation.customrow` and attaches when a `BottomTabs` view with custom items appears.
- `BottomTabs.setExternalCustomItemViewHost(true)` prevents the legacy overlay path from re-parenting React views into native cells.
- No changes required in app `MainApplication` — the module registers via `NavigationPackage`.

## Updating `customRow` at runtime

```js
Navigation.mergeOptions('BOTTOM_TABS_LAYOUT_ID', {
  bottomTabs: {
    customRow: {
      backgroundColor: '#1c1c1e',
      cornerRadius: 20,
    },
  },
});
```

On Android, merged `customRow` is picked up on the next layout pass via `BottomTabsCustomRowConfigStore`.

## Related API

- [`bottomTab.component`](api/options-bottomTab.mdx#component)
- [`bottomTabs.customRow`](api/options-bottomTabs.mdx#customrow)
- [Bottom tabs guide](bottomTabs)

---

### Docs Docs Deep Linking (`website/docs/docs/docs-deep-linking.mdx`)

---
id: deep-linking
title: Deep Linking
sidebar_label: Deep Linking
---

Deep linking opens a specific screen in your app from a URL — whether from a custom scheme (`myapp://user/42`) or a universal link (`https://myapp.com/user/42`). React Native Navigation maps URLs to screens and **presents the matched content as a modal** on top of whatever the user is currently doing, so their navigation state is preserved when they dismiss the modal.

## Setting up linking

Call `Navigation.setLinking()` once during app startup, alongside your `Navigation.registerComponent` calls:

```js
import { Navigation } from 'react-native-navigation';

Navigation.setLinking({
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Profile: 'user/:id',
      Settings: {
        path: 'settings',
        screens: {
          Notifications: 'notifications',
        },
      },
    },
  },
});
```

When a deep link arrives:

1. RNN parses the URL, strips the longest matching prefix, and matches the path against the `screens` tree.
2. The matched chain is wrapped in a `stack` and presented via `showModal`. The user can dismiss the modal to return to their previous flow.
3. If no route matches, the optional `fallback` callback is invoked.

Path parameters (`:id`) and query parameters are extracted and passed as `passProps` to each component in the modal.

## Configuration

### `prefixes`

Array of URL prefixes your app handles. Custom schemes and universal-link hosts are both supported. The longest matching prefix wins.

```js
prefixes: ['myapp://', 'https://myapp.com', 'https://myapp.com/v2'],
```

### `config.screens`

Map of screen names (must match the names you registered with `Navigation.registerComponent`) to URL path patterns.

**String value** — a leaf route:

```js
screens: {
  Home: 'home',          // matches myapp://home
  Profile: 'user/:id',   // matches myapp://user/42, extracts { id: '42' }
}
```

**Object value** — a route with nested children:

```js
screens: {
  Settings: {
    path: 'settings',
    screens: {
      Notifications: 'notifications',
      Account: 'account/:section',
    },
  },
}
// myapp://settings/notifications      → stack: [Settings, Notifications]
// myapp://settings/account/billing    → stack: [Settings, Account] with { section: 'billing' }
```

**Object value with no `path`** — a grouping node that contributes a screen to the chain but consumes no URL segments:

```js
screens: {
  Main: {
    screens: {
      Feed: 'feed',     // matches myapp://feed → stack: [Main, Feed]
      Search: 'search',
    },
  },
}
```

### Path parameters

Use `:paramName` in a pattern segment to capture it. Path params are merged with query params and handed to that segment's component as `passProps`. Path params win on key collision.

```js
screens: { Post: 'user/:userId/post/:postId' }

// myapp://user/5/post/99
// → Post screen receives passProps: { userId: '5', postId: '99' }
```

### Query parameters

Query string values are parsed automatically and merged into every segment's `passProps`:

```
myapp://search?q=hello&page=2
→ Search screen receives passProps: { q: 'hello', page: '2' }
```

#### Reserved keys

The query/path keys `ref` and `key` are **not** forwarded as `passProps`. React reserves these names (`ref` is consumed by React itself; passing a string `ref` to a component crashes under React 19's stricter validation). RNN silently drops them and logs a dev-mode warning. Rename any conflicting URL parameters before they reach your links:

```
myapp://user/42?ref=push   →  passProps: { id: '42' }       (ref dropped + warning)
myapp://user/42?source=push →  passProps: { id: '42', source: 'push' }
```

## Customizing presentation

By default, every matched link becomes a modal containing a stack with the matched chain pushed in order. If you need to customize either the layout or the navigation command itself, the config exposes two hooks.

### `getModal` — customize the modal layout

Provide a function that returns the `Layout` to present. Useful for adding default options, wrapping in a different layout, or skipping certain matches conditionally.

```js
Navigation.setLinking({
  // ...
  getModal: (match) => ({
    stack: {
      children: match.path.map((segment) => ({
        component: {
          name: segment.screen,
          passProps: { ...match.queryParams, ...segment.params },
          options: {
            topBar: {
              leftButtons: [{ id: 'close', text: 'Close' }],
            },
          },
        },
      })),
    },
  }),
});
```

Return `undefined` from `getModal` to skip presenting a modal for a particular match (e.g. ignore certain paths).

### `onLink` — full escape hatch

For complete control — pushing onto an existing stack instead of showing a modal, dismissing existing modals first, or composing multiple commands — provide `onLink`. When supplied, RNN does not present anything itself; you call navigation commands yourself.

```js
Navigation.setLinking({
  // ...
  onLink: (match) => {
    const leaf = match.path[match.path.length - 1];

    if (leaf.screen === 'Profile') {
      Navigation.push('mainStack', {
        component: {
          name: 'Profile',
          passProps: { id: leaf.params.id },
        },
      });
      return;
    }

    Navigation.showModal({
      stack: {
        children: match.path.map((segment) => ({
          component: { name: segment.screen, passProps: segment.params },
        })),
      },
    });
  },
});
```

When `onLink` is set, `getModal` is ignored.

## Match payload

Both `getModal` and `onLink` receive the same `RouteMatch` object:

```ts
interface RouteMatch {
  url: string;
  path: RouteMatchSegment[];
  queryParams: Record<string, string>;
}

interface RouteMatchSegment {
  screen: string;
  params: Record<string, string>;
}
```

## Fallback for unmatched URLs

If a received URL has no matching prefix or doesn't match any configured route, the optional `fallback` callback is invoked. Use it for logging, analytics, or routing to a "not found" screen.

```js
Navigation.setLinking({
  // ...
  fallback: (url) => {
    console.warn(`Unhandled deep link: ${url}`);
  },
});
```

## Deferred deep links

Two readiness gates control when links are processed; both must be open before a link is dispatched.

### Automatic root gate

RNN automatically defers link processing until your first `Navigation.setRoot()` resolves. This handles the common case where the OS delivers an initial URL before your app has a root window — the link is queued and replayed once `setRoot` mounts the root.

You don't need to opt into this behavior; it always applies.

### Optional `isReady` gate

For application-level gates such as authentication, supply an `isReady` predicate. The predicate is consulted on every incoming link; when it returns `false`, the link is queued. Once the gate opens, call `setLinkingReady(true)` to flush queued links in order.

```js
let isAuthenticated = false;

Navigation.setLinking({
  prefixes: ['myapp://'],
  config: { screens: { Profile: 'user/:id' } },
  isReady: () => isAuthenticated,
});

async function onLoginSuccess() {
  isAuthenticated = true;
  Navigation.setLinkingReady(true);
}
```

`setLinkingReady(true)` overrides `isReady` once called, so you can also drive the gate purely with explicit calls if you prefer.

## Manual handling

Some links don't arrive via the system URL handler — push-notification payloads, branch.io tokens, App Clips. Feed them into the same pipeline with `Navigation.handleDeepLink(url)`:

```js
Navigation.handleDeepLink('myapp://user/42?source=notification');
```

This runs the URL through parse → match → present exactly like a system-delivered link, including readiness gates.

If you'd rather hand the URL off natively (e.g. from a `UNUserNotificationCenterDelegate` you already maintain), call `[self dispatchDeepLinkURL:url]` inside your `RNNAppDelegate` subclass — same behavior, with cold-start queueing built in. See [Native setup → iOS → Notification taps](#ios) for an example.

## Complete example

```js
import { Navigation } from 'react-native-navigation';

Navigation.registerComponent('Home', () => require('./screens/Home').default);
Navigation.registerComponent('Profile', () => require('./screens/Profile').default);
Navigation.registerComponent('Settings', () => require('./screens/Settings').default);
Navigation.registerComponent('Notifications', () => require('./screens/Notifications').default);

let isLoggedIn = false;

Navigation.setLinking({
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Profile: 'user/:id',
      Settings: {
        path: 'settings',
        screens: { Notifications: 'notifications' },
      },
    },
  },
  isReady: () => isLoggedIn,
  fallback: (url) => console.warn(`Unhandled: ${url}`),
});

Navigation.events().registerAppLaunchedListener(() => {
  Navigation.setRoot({
    root: { stack: { children: [{ component: { name: 'Home' } }] } },
  });
});

export function onLoginComplete() {
  isLoggedIn = true;
  Navigation.setLinkingReady(true);
}
```

With this configuration:

- `myapp://home` opens the Home screen as a modal on top of the current screen.
- `myapp://user/42` opens Profile as a modal with `{ id: '42' }` as props.
- `myapp://settings/notifications` opens a modal containing a stack with `Settings` → `Notifications` pushed in order.
- Links arriving before `setRoot` resolves are queued automatically and replayed.
- Links arriving before login are queued and replayed when `onLoginComplete()` runs.

## Native setup

The framework consumes URLs from React Native's `Linking` API. You still configure the URL schemes and universal links at the platform level — but, unlike most React Native apps, you don't need to hand-write `application:openURL:` or `application:continueUserActivity:` glue. As long as your `AppDelegate` subclasses `RNNAppDelegate`, custom-scheme openings and universal links are forwarded to JS automatically, including cold-start URLs that arrive before the React runtime is ready.

### iOS

**1. Register your URL scheme in `Info.plist`:**

```xml
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>
```

**2. (Optional) Universal links.** Add the Associated Domains entitlement and host an `apple-app-site-association` file — see [Apple's docs](https://developer.apple.com/documentation/xcode/supporting-associated-domains). `RNNAppDelegate` already implements `application:continueUserActivity:restorationHandler:` and forwards browser-activity URLs through the same pipeline.

**3. (Optional) Notification taps.** Notifications aren't routed automatically because most apps already own `UNUserNotificationCenter.current.delegate` via Firebase / OneSignal / etc. From your existing notification handler, hand the URL off to RNN:

```objc
#import "AppDelegate.h"  // your subclass of RNNAppDelegate
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [super application:application didFinishLaunchingWithOptions:launchOptions];
  [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  return YES;
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
  completionHandler(UNNotificationPresentationOptionBanner |
                    UNNotificationPresentationOptionList |
                    UNNotificationPresentationOptionSound);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler {
  NSString *urlString = response.notification.request.content.userInfo[@"url"];
  if ([urlString isKindOfClass:[NSString class]]) {
    [self dispatchDeepLinkURL:[NSURL URLWithString:urlString]];
  }
  completionHandler();
}

@end
```

`dispatchDeepLinkURL:` is inherited from `RNNAppDelegate`. It safely handles cold-start (URLs arriving before the React runtime is ready are queued and flushed automatically once content first renders) so you can call it from anywhere — push handlers, deferred-deep-link SDKs, branch.io callbacks, etc.

The JS equivalent is `Navigation.handleDeepLink(url)`; use whichever fits the layer you're working at.

### Android

Add an intent filter to your `MainActivity` in `AndroidManifest.xml`:

```xml
<activity
  android:name=".MainActivity"
  android:launchMode="singleTask">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myapp" />
  </intent-filter>
</activity>
```

For App Links, add `android:autoVerify="true"` and host an `assetlinks.json`. See [Android's documentation](https://developer.android.com/training/app-links).

`NavigationActivity` already forwards both cold-start (`getIntent()`) and warm (`onNewIntent`) URLs to React Native's `Linking` module — no extra Java/Kotlin needed. Notification taps that carry a deep-link URI (via `PendingIntent` with `ACTION_VIEW`) flow through the same `onNewIntent` path automatically.

## API reference

### `Navigation.setLinking(config)`

Configure deep link handling. Subsequent calls reconfigure cleanly (the previous subscription is torn down).

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `prefixes` | `string[]` | Yes | URL prefixes to match. Longest wins. |
| `config.screens` | `ScreensConfig` | Yes | Screen-to-path mapping. |
| `getModal` | `(match) => Layout \| undefined` | No | Build a custom modal layout for the match. |
| `onLink` | `(match) => void` | No | Full escape hatch. Overrides default and `getModal`. |
| `fallback` | `(url) => void` | No | Called when a URL doesn't match any prefix or route. |
| `isReady` | `() => boolean` | No | Predicate gating link processing. |

### `Navigation.handleDeepLink(url)`

Feed a URL into the pipeline as if it had been delivered by the OS.

### `Navigation.setLinkingReady(ready)`

Set the user-controlled readiness gate. Passing `true` flushes queued links; passing `false` blocks future links until called again with `true`.

---

### Docs Docs ExternalComponent (`website/docs/docs/docs-externalComponent.mdx`)

---
id: externalComponent
title: External Component
sidebar_label: External Component
---

The ExternalComponent layout allows you to display any native view as a screen. To use the External Component we'll need to register it with a string name. This name is then used when declaring layouts in JS.

## Android
### Implementing the native component
When it comes to implementing an external component on Android, you have two choices. We recommend you use a base class extending `View`. If you're required to use Fragments, you'll find an basic example below.

#### ViewGroup
```java
public class ViewGroupComponent implements ExternalComponent {
    private final FrameLayout content;

    ViewGroupComponent(FragmentActivity activity, JSONObject props) {
        content = new FrameLayout(activity);
    }

    @Override
    public View asView() {
        return content;
    }
}
```

#### Fragment

Using a Fragment as an external component is done by attaching the Fragment to a FrameLayout, and returning the FrameLayout from the `asView()` method of the ExternalComponent.

```java
public class FragmentComponent implements ExternalComponent {
    private final FrameLayout content;

    FragmentComponent(FragmentActivity activity, JSONObject props) {
        // Create the FrameLayout to which we'll attach our Fragment to
        content = new FrameLayout(activity);
        content.setId(R.id.fragment_screen_content);
        // Attach the Fragment to the FrameLayout
        activity.getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_screen_content, createFragment(props))
                .commitAllowingStateLoss();
    }

    private FragmentScreen createFragment(JSONObject props) {
        FragmentScreen fragment = new FragmentScreen();
        // Pass the props sent from Js in a bundle
        Bundle args = new Bundle();
        args.putString("text", props.optString("text", ""));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View asView() {
        return content;
    }
}
```

### Registering the component
```java
public class MainApplication extends NavigationApplication {
  @Override
    public void onCreate() {
        super.onCreate();
        registerExternalComponent("MyExternalComponent", new FragmentCreator());
    }
}
```

## iOS
### ViewController registration

```objectivec
[ReactNativeNavigation registerExternalComponent:@"MyExternalComponent" callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
	return [[ExternalViewController alloc] initWithProps:props];
}];

```
## Using the component from JS
Once you've registered the external component in native, you can use it in your layout declarations.
For example, to show an external component modally:
```js
Navigation.showModal({
  externalComponent: {
    name: 'MyExternalComponent',
    passProps: {
      text: "Text from JS"
    }
  }
});
```

:::caution
props passed to external components are sent over the bridge and therefore must be serializable.
:::

---

### Docs Docs Functional Components (`website/docs/docs/docs-functional-components.mdx`)

---
id: functionalComponents
title: Using functional components as screens
sidebar_label: Using functional components
---

Both class components and functional components can be used as screens. There is no performance difference between the two. Deciding which type component to use boils down to user preference.

## Declaring static options
Static options are a great way to declare options close to where they are used. Declaring static options is done by first declaring the functional component, and then declaring the options on the function component.
```jsx
const MyScreen = (props) => {
  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
};

MyScreen.options = {
  topBar: {
    background: {
      color: 'red'
    }
  }
}
```

## Listening to navigation events
Navigation events let you react to various events related to a specific component or the app itself. Read more about them [here](/react-native-navigation/api/events)

```jsx
import { useEffect } from 'react';
import { Navigation } from 'react-native-navigation';

function MyScreen(props) {
  useEffect(() => {
    const listener = {
      componentDidAppear: () => {
        console.log('RNN', `componentDidAppear`);
      },
      componentDidDisappear: () => {
        console.log('RNN', `componentDidDisappear`);
      }
    };
    // Register the listener to all events related to our component
    const unsubscribe = Navigation.events().registerComponentListener(listener, props.componentId);
    return () => {
      // Make sure to unregister the listener during cleanup
      unsubscribe.remove();
    };
  }, []);

  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
}
```

In the example above, our listener is registered with the `componentId` passed in the second argument, and will receive only its related events.

:::tip
[underscopeio/react-native-navigation-hooks](https://github.com/underscopeio/react-native-navigation-hooks) is a wonderful library which greatly simplifies usage with hooks by introducing dedicated hooks for each event. The following example, which is taken from their docs, shows how to listen to all appear events and a particular screen's appear events:

```jsx
import { useNavigationComponentDidAppear } from 'react-native-navigation-hooks'

const ScreenComponent = ({ componentId }) => {
  // Global listener
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} (${e.componentId}) appeared`)
  })

  // Listen events only for this screen (componentId)
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} appeared`)
  }, componentId)

  return (
    <View>
      <Text>Screen Component</Text>
    </View>
  )
}
```
:::

---

### Docs Docs Modal (`website/docs/docs/docs-modal.mdx`)

---
id: modal
title: Modal
sidebar_label: Modal
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

In human-centered design, when we speak about a modal (or modality), we often refer to a set of techniques, aimed at bringing user attention to a specific event / screen / action / etc. Those often require user input. A pop-up on a website, a file deletion confirmation dialogue on your computer, or an alert asking you to enable location service on your phone - these can all be considered modals.

A modal is a term used in native iOS world ([full description here](https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/)), while on Android, [dialogs](https://developer.android.com/guide/topics/ui/dialogs) are often used to create similar or identical behavior, alongside other techniques.

## Presenting modals

Modal can be displayed by invoking the `Navigation.showModal()` command, as shown in the example below:

```js
Navigation.showModal({
  stack: {
    children: [
      {
        component: {
          name: 'MODAL_SCREEN',
          options: {
            topBar: {
              title: {
                text: 'Modal',
              },
            },
          },
        },
      },
    ],
  },
});
```
Or by declaring modal as a Component inside render function:

:::note
Available for Android only, for iOS please use Modal from `react-native`.
:::

([Full code can be found in the Playground](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/ModalScreen.tsx)).

```jsx
import { NavigationComponent, Modal as RNNModal } from 'react-native-navigation';
.....
toggleModal = () => this.setState({ modalVisible: !this.state.modalVisible });
.....
render() {
  return (
    .....
  <RNNModal
      onShow={/* optional callback */}
      animationType={/* optional, 'none' | 'fade' | 'slide', default 'slide'*/}
      blurOnUnmount={/* optional, default false */}
      transparent={/* optional, default false, true behaves as overCurrentContext */}
      visible={this.state.modalVisible}
      onRequestClose={() => this.setState({ modalVisible: false })}
      >
          <Button
            label="Dismiss declared Modal"
            testID={DISMISS_MODAL_BTN}
            onPress={this.toggleModal}
          />
          ....
    </RNNModal>
    ....
    );
}
```

Here's how the Modal looks on both platforms.

<Tabs
  defaultValue="ios"
  values={[
    { label: 'iOS', value: 'ios' },
    { label: 'Android', value: 'android' },
  ]}
>
  <TabItem value="ios">
    <img width="40%" src={useBaseUrl('img/modal_ios.gif')} />
  </TabItem>
  <TabItem value="android">
    <img width="40%" src={useBaseUrl('img/modal_android.gif')} />
  </TabItem>
</Tabs>

## Adding a dismiss button

Modals should always have a dismiss button, on left-to-right devices it's typically placed as a left button in the TopBar.

After we've added our dismiss button, we need to dismiss the modal when the button is pressed.

:::note
For the LeftButton to be visible, the screen must be displayed in a Stack.
:::

```js
class ModalScreen extends React.Component {
  // Set a dismiss button in static options
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'dismiss',
          icon: require('./dismiss.png'),
        },
      },
    };
  }

  constructor(props) {
    super(props);
    // Register to events
    Navigation.events().bindComponent(this);
  }

  // Handle the button press event and dismiss the modal if needed
  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'dismiss') {
      Navigation.dismissModal(this.props.componentId);
    }
  }
}
```

## Transparent modals

Showing transparent modals is a nice technique to increase immersiveness while keeping the user in the same context.
When a modal is displayed the content behind it (either root or modal) is removed from hierarchy. While this behavior improves performance, it's undesired when
showing transparent modals as we need to see the content behind it.

To configure this behaviour, we'll need to change the `modalPresentationStyle` option to `overCurrentContext` and change the layout background color to `'transparent'`.

```js
{
  modalPresentationStyle: 'overCurrentContext',
  layout: {
    backgroundColor: 'transparent'
  }
}
```

## Preventing a Modal from being dismissed

Preventing a modal from being dismissed is done differently for each platform. While preventing the user from dismissing the modal is possible,
the modal could still be dismissed programmatically by calling `Navigation.dismissModal()`

If the modal has a dismiss button, of course you'll need to handle it your self and avoid calling `Navigation.dismissModal()`
when the button is pressed.

### Android

On Android, modals can be dismissed with the hardware back button. You can handle the back press yourself by
disabling the hardware back button `dismissModalOnPress` option:

```js
{
  hardwareBackButton: {
    dismissModalOnPress: false;
  }
}
```

As a result, pressing the hardware back button will not dismiss the modal and will dispatch [`navigationButtonPress`](https://wix.github.io/react-native-navigation/api/events#navigationbuttonpressed-event) event with the default hardware back button id `RNN.hardwareBackButton`.

### iOS

While iOS devices don't have a hardware back button, PageSheet modals can be dismissed by swipe gesture
from the top of the screen. To disable it, set [swipeToDismiss](#) option to false.

## Presentation Style

The [presentation style](/react-native-navigation/api/options-root#modalpresentationstyle) determines the look and feel of a screen displayed as modal.

---

### Docs Docs Overlay (`website/docs/docs/docs-overlay.mdx`)

---
id: overlay
title: Overlay
sidebar_label: Overlay
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Overlays are used to layout content on top of all other layout hierarchies, while fitting the screen bounds.
The contents displayed in an Overlay can either be non-obtrusive, like Toasts and Snackbars, or an Alert that blocks all interactions with any content behind it. The view contained within it should be aligned either with absolute position, flex, or with margins, all according to your needs.

## Handling touch events outside the view

When showing views like Alert or Toast in an Overlay, you would want to configure if you want to allow users to interact with content behind the alert. This is done via the [interceptTouchOutside](#) option.

## Overlay examples

<Tabs
  defaultValue="alert"
  values={[
    { label: 'Alert', value: 'alert', },
    { label: 'Toast', value: 'toast', }
  ]
}>
<TabItem value='alert'>

The example below demonstrates how to create a simple alert dialog using an Overlay. Touch events outside the alert will be blocked and won't pass through to the content behind the alert since we're specifying `interceptTouchOutside: true` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/alert_android.png')} />

```jsx
const React = require('react');
const { Text, Button, View } = require('react-native');
const { Navigation } = require('react-native-navigation');

function Alert({ componentId, title, message }) {
  const dismiss = () => Navigation.dismissOverlay(componentId);

  return (
    <View style={styles.root}>
      <View style={styles.alert}>
        <Text style={styles.title}>{title}</Text>
        <Text style={styles.message}>{message}</Text>
        <Button title="OK" onPress={dismiss} />
      </View>
    </View>
  );
}

const styles = {
  root: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#00000050',
  },
  alert: {
    alignItems: 'center',
    backgroundColor: 'whitesmoke',
    width: 250,
    elevation: 4,
    padding: 16,
  },
  title: {
    fontSize: 18,
  },
  message: {
    marginVertical: 8,
  },
};

Alert.options = (props) => {
  return {
    overlay: {
      interceptTouchOutside: true,
    },
  };
};

module.exports = Alert;
```

</TabItem>
<TabItem value='toast'>

The example below demonstrates how to show a Toast using an Overlay. A user can interact with the content behind the toast since we've declared `interceptTouchOutside: false` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/toast_android.png')} />

```jsx
const React = require('react');
const { View, Text, StyleSheet, TouchableOpacity } = require('react-native');
const Colors = require('../commons/Colors');
const Navigation = require('../services/Navigation');

const Toast = function ({ componentId }) {
  return (
    <View style={styles.root}>
      <View style={styles.toast}>
        <Text style={styles.text}>This a very important message!</Text>
        <TouchableOpacity
          style={styles.button}
          onPress={() => Navigation.dismissOverlay(componentId)}
        >
          <Text style={styles.buttonText}>OK</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  root: {
    flex: 1,
    flexDirection: 'column-reverse',
  },
  toast: {
    elevation: 2,
    flexDirection: 'row',
    height: 40,
    margin: 16,
    borderRadius: 20,
    backgroundColor: Colors.accent,
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  text: {
    color: 'white',
    fontSize: 16,
    marginLeft: 16,
  },
  button: {
    marginRight: 16,
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
});

Toast.options = {
  layout: {
    componentBackgroundColor: 'transparent',
  },
  overlay: {
    interceptTouchOutside: false,
  },
};

module.exports = Toast;
```

</TabItem>
</Tabs>

---

### Docs Docs Passing Data To Components (`website/docs/docs/docs-passing-data-to-components.mdx`)

---
id: passing-data-to-components
title: Passing data to components
sidebar_label: Passing data to components
---

## Initial props

React components use [props](https://facebook.github.io/react-native/docs/props) to receive data when they are created. When displaying the [component](../api/layout-component) layout, you can pass initial props to components using the `passProps` property.

In this example, we push the `UserProfile` screen and pass two initial props to it:

```js
Navigation.push(this.props.componentId, {
  component: {
    name: 'UserProfile',
    id: 'PROFILE_SCREEN_ID'
    passProps: {
      name: 'John Doe',
      status: 'online'
    }
  }
});
```

:::tip Serialization
passProps don't need to be serializable. You can use this mechanism to pass lambda functions or even React Components.
:::

## Handling passProps in static options

Each component can have a static options property which is used to configure the style properties of elements on the screen when that component is displayed. 

Static options can either be a simple object, or a function which accepts `passProps` as an argument. Sometimes when declaring components, not all style properties are known. For example, a user profile screen will usually have the user's name as the TopBar title text. Therefore the title must be configured dynamically when pushing the screen.

Following the code example [above](passing-data-to-components#initial-props), lets see how to use props passed in the push command to set the TopBar title.

```jsx
class UserProfileScreen extends React.Component {
  static options(props) {
    return {
      topBar: {
        title: {
          text: props.name
        }
      }
    };
  }
}
```

## Updating props

To update a component's props, use the [Navigation.updateProps()](../api/component#updateprops) command. Updating props triggers the component lifecycle methods related to [updating](https://reactjs.org/docs/react-component.html#updating).

Notice that we're using the component `id` in order to update props of this specific instance of the component.

```js
Navigation.updateProps('PROFILE_SCREEN_ID', {
  status: 'offline'
});
```

---

### Docs Docs Playground App (`website/docs/docs/docs-playground-app.mdx`)

---
id: playground-app
title: Playground app
sidebar_label: Playground app
---

### Running The Project

If you want to have a quick look around and test things out, you can run the playground app, bundled with this repo.

1. Install dependencies via `yarn install` (if you haven't already) and `yarn pod-install` (for iOS)
2. Run the playground project on Android and iOS
    - `yarn start` to get the packager running in the terminal, leave it open
    - **iOS**: open `./playground/ios/playground.xcworkspace` in Xcode and run it
    - **Android**: open `./playground/android` in Android Studio and run it
3. You can run tests if / when you need to (list of scripts [available here](meta-contributing#scripts)). Before
you start changing things, make sure everything works.
	- To easily run all tests in parallel `yarn test-all`

---

### Docs Docs Root (`website/docs/docs/docs-root.mdx`)

---
id: root
title: Root
sidebar_label: Root
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

The root is where the application layout structure is defined. It is typically the first UI element a user interacts with. The root can be changed multiple times during the lifespan of the application. For example, if an app requires users to login, it's common to use a stack-based root and transition to either tabs- or SideMenu-based root if login is successful.

## Setting root on app launch
RNN exposes an appLaunched listener which is invoked whenever root needs to be set.

On iOS, the app launched event is usually emitted once in the lifespan of the application - when the app is opened for the first time. On Android things become a little bit more complicated. Like on iOS, the event is emitted when an app is opened for the first time. Since the system can destroy the Activity when the app is in the background to free resources, the event is emitted when the app returns to foreground after the activity has been destroyed.

```js
Navigation.events().registerAppLaunchedListener(() => {
  Navigation.setRoot({
    root: {

    }
  });
});
```

:::important
registerAppLaunchedListener() must be called as soon as the bundle is executed. Otherwise the event, which is emitted from native to JS, won't be handled at the correct moment in time.
::::

## Conditional initial root
A common use case is to set the initial root according to a condition of some sort. For example:

> If a user is logged in, show the application main root; otherwise show a login screen.

To do this, simply set the appropriate root according to your needs.
```js
Navigation.events().registerAppLaunchedListener(() => {
  if (isUserLoggedIn()) {
    setMainRoot();
  } else {
    setLoginRoot();
  }
});
```

## Common root structures

<Tabs
  defaultValue='stack'
  values={[
    { label: 'Stack root', value: 'stack' },
    { label: 'BottomTabs root', value: 'bottomTabs' },
    { label: 'SideMenu root', value: 'sideMenu' }
  ]
}>

<TabItem value='stack'>
Stacks are usually used as root for small scale apps or for short-lived flows within one big app. For example, here's a login flow:

```js
Navigation.setRoot({
  root: {
    stack: {
      children: [
        {
          component: {
            name: 'LOGIN_SCREEN'
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='bottomTabs'>
Typically, stacks are used as direct children of BottomTabs and each child is an independent root. This lets users seamlessly switch between tabs as each tab has its own navigation hierarchy.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      children: [
        {
          stack: {
            children: [
              {
                component: {
                  name: 'FEED_SCREEN'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'CHAT_LIST'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'PROFILE_SCREEN'
                }
              }
            ]
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='sideMenu'>
When a SideMenu layout is used as root, the center screen would typically be a stack. The center stack should be treated as a root - you can push child screens into it, or replace it alltogether by calling `setStackRoot`.

```js
Navigation.setRoot({
  root: {
    sideMenu: {
      center: {
        stack: {
          children: [
            {
              component: {
                name: 'HOME_SCREEN'
              }
            }
          ]
        }
      },
      left: {
        component: {
          name: 'MENU_SCREEN'
        }
      }
    }
  }
});
```

</TabItem>
</Tabs>

---

### Docs Docs Screen Lifecycle (`website/docs/docs/docs-screen-lifecycle.mdx`)

---
id: screen-lifecycle
title: Screen Lifecycle
sidebar_label: Screen Lifecycle
---

Any React Component registered with react-native-navigation is enhanced with two additional lifecycle events:

* `componentDidAppear` - called each time a component is revealed to the user
* `componentDidDisappear` - called each time a component is hidden from user's view **as a result of being detached from hierarchy**

These methods compliment React's lifecycle methods:

* `componentDidMount` - called once, when a component is attached to hierarchy **for the first time**
* `componentWillUnmount` - called once, when a component is destroyed

### Mounting
These methods are called in the following order when a component is created and attached to hierarchy.

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

### Unmounting
These methods are called when a component is being removed from hierarchy

* componentDidDisappear()
* componentWillUnmount()

### Modal

When a modal is displayed, depending on the [modalPresentationStyle](/react-native-navigation/api/options-root#modalpresentationstyle), content behind it might be detached from hierarchy. This affects the visibility events which are emitted to the content behind the modal.

When Modals with `pageSheet` or `overCurrentContext` modalPresentationStyle are displayed, previous content is still visible to the user. Thus `componentDidDisappear` event is **not** emitted.

Same is applied when a modal is dismissed. If it was originally presented with `pageSheet` or `overCurrentContext` modalPresentationStyle, when that modal is then dismissed, the previous context won't receive a `componentDidAppear` event.

### Overlay
These methods are called in the following order when a component is displayed as an Overlay:

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

:::note
Content displayed behind an Overlay does not receive the `componentDidDisappear`, since it's still visible to user and attached to the hierarchy.
:::

---

### Docs Docs Showcases (`website/docs/docs/docs-showcases.mdx`)

---
id: showcases
title: Showcases
sidebar_label: Showcases
---

## Apps
### Hekla for Hacker News

A hacker news client built from the ground up with v2 of react-native-navigation.

It is a tab-based app and utilizes Split Layout for iOS tablets, 3D touch and more.

- [Source code](https://github.com/birkir/hekla)
- [Download iOS](https://itunes.apple.com/us/app/hekla/id1405096983?mt=8)
- [Download Android](https://play.google.com/store/apps/details?id=is.pipe.hekla)

## Starter Kits
* [kanzitelli/expo-rnn-starter](https://github.com/kanzitelli/expo-rnn-starter) - Simple yet practical starter with React Native Navigation and [Expo Modules](https://docs.expo.io/bare/installing-unimodules/), [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) and [Redux](https://github.com/reduxjs/redux) (pick one) and more goodies inside such as Typescript, [RNN Hooks](https://github.com/underscopeio/react-native-navigation-hooks), [RN Vector Icons](https://github.com/oblador/react-native-vector-icons), [RN Gesture Handler](https://github.com/kmagiera/react-native-gesture-handler). As an example, basic Reddit App implemented in two ways: using [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) in `/srcMobX` and using [Redux](https://github.com/reduxjs/redux) in `/srcRedux`.
* [atoami/react-native-navigation-redux-starter-kit](https://github.com/atoami/react-native-navigation-redux-starter-kit) - React Native Navigation(v2) Starter Kit with Redux, Saga, ESLint, Babel and Jest 😎
* [alexwasner/react-native-mobx-firebase-starter](https://github.com/alexwasner/react-native-mobx-firebase-starter) - A React Native starter app with React Native Navigation(v2), MobX, Firebase, Lottie and More 🤓
* [hsyndeniz/react-native-quick-start](https://github.com/hsyndeniz/react-native-quick-start) - A React Native starter app with React Native Navigation, Redux, Firebase, Social Auth, Phone Auth, Push Notifications, Google Maps, Google Admob, Lottie and More 🤓
* [svbutko/react-native-template-strong](https://github.com/svbutko/react-native-template-strong) - Quick, opinionated, documented and strong beginning for your next project. React Native Navigation, TypeScript, Redux ToolKit are the core, and it also includes many more dependencies (tests, linters are included) 💪

### Playground

The playground example is a place where we showcase and test all features of react-native-navigation.

```bash
git clone https://github.com/wix/react-native-navigation
cd react-native-navigation
yarn install

# for iOS:
yarn pod-install # Install iOS pods
yarn xcode # Opens XCode
yarn start # Starts the packager

# for Android:
# 1. open Android Studio inside "./playground/android"
# 2. start an emulator
yarn start # Start the packager

# Run the app in Simulator or on Device from within XCode/Android Studio
```

---

### Docs Docs SideMenu (`website/docs/docs/docs-sideMenu.mdx`)

---
id: sideMenu
title: Side Menu
sidebar_label: Side Menu
---

SideMenu provides access to destinations in the app from an easy to access menu which is accessible to the user via horizontal swipe gesture or a menu button.

## Opening programmatically

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu. The menu is opened by setting its visible option to visible.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Opening via the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button at the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this.props.componentId, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

## Pushing to the center layout from a menu
A common use case when using SideMenus is to interact with the center layout, e.g. pushing a screen to a stack in the center layout when a user clicks on a button from one of the menus.

In order to interact with the stack, we'll first assign it a predefined id. For example:

```js
sideMenu: {
  center: {
    stack: {
      id: 'CenterStack',
      children: []
    }
  },
  left: {
    ...
  }
}
```

Now that we've defined an `id` for out stack, we can go ahead and push our screen to it. If we're pushing while the SideMenu is open, we'll need to make sure we close it by updating the visibility option of the relevant menu (left or right).

```js
Navigation.push('CenterStack', {
  component: {
    name: Screens.Pushed,
    options: {
      sideMenu: {
        left: {
          visible: false
        }
      }
    }
  }
});
```

---

### Docs Docs Stack (`website/docs/docs/docs-stack.mdx`)

---
id: stack
title: Stack
sidebar_label: Stack
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

A stack is a container layout promoting a hierarchical navigation. It is used for navigating between screens at consecutive levels of hierarchy, steps in a flow or across an app.

The first child in the stack (represented by the `children` array) is the root and is displayed at the bottom of the stack. The last child in the children array is the child currently being displayed.

In this layout, only a single child screen is visible at any given time and consecutive screen can be added to the top of the stack using the `Navigation.push` command. Tapping the back button will pop the stack and remove the top most screen.

The stack manages the TopBar at the top of the stack. The TopBar displays the current screens' title and buttons. It can be hidden with the `topBar: { visible: false }` option. By default, screens are rendered below the TopBar. This behavior can be changed by setting `topBar: { drawBehind: true }` in the current screens' options.

# Layout Examples

<Tabs
  defaultValue="single"
  values={[
    { label: 'Single child', value: 'single', },
    { label: 'Multiple Children', value: 'multiple', }
  ]
}>
<TabItem value="single">


A stack declared with a single child.

```js
const stack = {
  children: [
    {
      component: {
        name: 'MyComponent',
      },
    },
  ],
};
```

</TabItem>
<TabItem value="multiple">


A stack can be initialized with more than one child, in which case the last child will be the currently displayed child and the first child will be hidden. In this case the back button will be visible automatically, clicking it will go back in the stack revealing the first (previous) child.
Once the root child becomes visible, the back button is hidden.

```js
const stack = {
  children: [
    {
      component: {
        name: 'RootComponent',
      },
    },
    {
      component: {
        name: 'SecondComponent',
      },
    },
  ],
};
```

</TabItem>
</Tabs>


## TopBar Buttons

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

:::tip Always assign titles to buttons!
When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.
:::

### Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](../api/options-button#showasaction) options to control when the button should appear in the menu.

### Using a react component in a button

Sometimes we require more from our buttons. In order to support every product need, React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as their custom view:

```js
topBar: {
  rightButtons: [
    {
      id: 'custom',
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

### Updating props of custom buttons

To update props of a mounted component used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger Reacts component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0,
        },
      },
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

### Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

#### Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

#### Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

## Back Button

The back button is added automatically when two or more screens are pushed into the stack.

### Styling the back button

The back button's style can be customized by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

### Controlling visibility

The back buttons visibility can be controlled with the visible property.

```js
backButton: {
  visible: false;
}
```

### Changing visibility programmatically

Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false,
  },
});
```

## Interacting programmatically

The Navigation object provides ways to programmatically manipulate the stack.

### Interact with the Stack by componentId

Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN',
      },
    });
  };
}
```

### Interact with the Stack by a predefined id

Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent',
          },
        },
      ],
    },
  },
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen',
    },
  });
}
```

---

### Docs Meta Contributing (`website/docs/docs/meta-contributing.mdx`)

---
id: meta-contributing
title: Contributing
sidebar_label: Contributing
---

Thank you for showing interest in contributing to React-Native-Navigation! This project is developed and maintained by Wix in collaboration with the community.

There are various ways in which you can contribute to this library, not all require knowledge or expertise in native development. Listed below is all you need to get started with your first contribution.

## Stack Overflow

Stack Overflow is used by developers to find answers and troubleshoot code. Users are encouraged to post questions on SO and tag them with the [wix-react-native-navigation](https://stackoverflow.com/questions/tagged/wix-react-native-navigation) tag. Answering issues on SO is very helpful and beneficial to the community, only this time, there's a personal angle - you can boost your SO ranking and rack up points quickly.

## Discord

Another popular communication channel is our [Discord channel](https://discord.gg/DhkZjq2) where users post questions and consult with each other. You're welcome to join the discussions and answer questions. This is also a great place to meet other community members and project maintainers.

## Contributing to React-Native-Navigation

### iOS

There are 2 ways to test your contribution to this project on iOS:

1. You can contribute and test your changes using the playground provided.


2. You can install React-Native-Navigation in a new or existing project and set your project to use your local clone of React-Native-Navigation in the podfile.
The following steps are required in order to make the project work with your local environment:

#### 2.1

Install React-Native-Navigation as you'll usually do in your project, using `yarn add react-native-navigation` or `npm install --save react-native-navigation`.

#### 2.2

Add the following configuration to the `react-native.config.js` file, at the root of your project.

```javascript
module.exports = {
	project: {
		ios: {},
		android: {},
	},
	dependencies: {
		'react-native-navigation': {
			platforms: {
				ios: null,
				android: null
			},
		},
	},
};
```

#### 2.3

Clone the project using `git clone https://github.com/wix/react-native-navigation` at your desired location.

#### 2.4

Add the following line in the Podfile:

```ruby
pod 'ReactNativeNavigation', :path => '/path/to/cloned/react-native-navigation'
```

You're done. Happy coding!

## GitHub Issues

### Open an issue
Found a bug? Missing a feature? Go ahead and open an issue! Make sure to add all details mentioned in the issue template. If you're interested in suggesting a big change, please speak to one of the admins on [Discord](#discord) to coordinate your effort.

### Respond to issues
Although the issue tracker is used solely for bug reports, issues are frequently opened for questions or to request assistance. As the project grows in popularity, more issues remain unanswered for long periods of time.

Some issues can be trivial and easy to pinpoint - a missing import statement or apostrophe, wrong layout structure, etc. If you're an experienced user, helping out newcomers can be quite satisfying and allows maintainers to focus on features and bug fixes.

Some issues are tagged as ["looking for contributors"](https://github.com/wix/react-native-navigation/labels/user%3A%20looking%20for%20contributors). These issues have been recognized by the team, but aren't prioritized by Wix developers due to lack of time or for some other reason. We leave these issues to our community and you're more than welcome to take a crack at them. If you'd like to submit a PR, see [these instructions](#running-the-project) on how to run the project locally.

### Provide reproductions
Reproducing bugs takes time. Lots of time. Usually that's because an issue is lacking important information, which then causes lots of back and forth communication between maintainers and users. Help us address more bugs and issues by providing reproductions.

Providing reproductions improves the chances of an issue being prioritized by maintainers!

If an issue is reproduced with a specific combination of options, posting these options will usually suffice. If a specific layout structure is involved or specific actions need to be performed in a certain order - then we ask that you fork the project and push a branch with a reproduction to the Playground app.

Check out the [list of issues requiring reproductions](https://github.com/wix/react-native-navigation/labels/user%3A%20requires%20reproduction).

## Submitting PRs
So you've fixed a bug or added a feature and you're ready to submit a pull request 🎉🎊 Make sure the title is clear and describes the reason for the PR. Please include any information you can which will help us understand the reasons for the PR, what it fixes and what it changes. Please include before/after pictures/gifs when appropriate.

## Workflow
This project is driven by tests. Before implementing any feature or fixing any bug, a failing test (e2e or unit or both) should be added, depending on the environment of where the fix should be implemented. For example, for an API change, a failing e2e should be written. For a small bug fix in Android, for example, a unit test in Android should be added.

This will ensure good quality throughout the life of the project and will help avoid unexpected breakages.

No PR will be accepted without adequate test coverage.

If you need help running the project, have a look at the [Playground app](playground-app) section. You can run the tests using the scripts below.


### Tests and the Playground app
Besides an overview of basic React Native Navigation functionality, the [Playground app](playground-app) can (and rather should) be used for e2e tests and reproductions. If your change requires an e2e, add it to the playground app, to the appropriate screen. Again, quick setup instructions available in [Playground app](playground-app) section of these docs.

:::tip
If a screen contains too many buttons, e2e tests might fail if the button is positioned out of screen bounds because Detox matchers detect it's invisible.
:::

### Enable linter
The project uses [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) to ensure code style consistency across the codebase. Make sure to install these plugins in your IDE.

A pre-commit hook will verify that the linter passes when committing.

### Project Folder Structure

| Folder | Description |
| ------ | ----------- |
| `src` | TypeScript sources and unit tests |
| `android` | Android sources and unit tests |
| `ios` | iOS sources and unit tests |
| `lib` | Compiled JavaScript and TypeScript definitions (generated by `react-native-builder-bob`) |
| `lib/module/index.js` | The entry point for `import Navigation from 'react-native-navigation'` |
| `playground` | The playground app workspace. Contains its own `src`, `android`, `ios`, and `package.json`. All e2e tests run against this app. |
| `playground/e2e` | [detox](https://github.com/wix/detox) e2e tests on both Android and iOS |
| `integration` | Misc JavaScript integration tests, proving integration with other libraries like redux |
| `scripts` | All build and test scripts |
| `autolink` | Autolinking scripts for React Native CLI |

### Scripts

This project uses [Yarn workspaces](https://yarnpkg.com/features/workspaces). The root workspace contains the main library, and the `playground` workspace contains the playground app for testing.

| Command | Description |
| ------- | ----------- |
| `yarn install` | installs dependencies for all workspaces |
| `yarn prepare` | compiles TypeScript sources `./src` into JavaScript `./lib` (runs automatically on install) |
| `yarn clean` | cleans all build directories, stops packager, fixes flakiness by removing watchman cache, etc. |
| `yarn start` | starts the react-native packager for local debugging |
| `yarn xcode` | for convenience, opens xcode in this project |
| `yarn pod-install` | installs iOS pods (runs `yarn workspace react-native-navigation-playground pod-install`) |
| `yarn install-android`  |  builds playground debug/release version and installs on running android devices/emulators. <br></br> **Options:** `-- --release` |
| `yarn uninstall-android` | uninstalls playground from running android devices/simulators |
| `yarn test-js` | runs javascript tests and coverage report |
| `yarn test-autolink` | runs autolink tests |
| `yarn test-unit-ios` | runs ios unit tests in debug/release <br></br> **Options:** `-- --release` |
| `yarn test-unit-android` | runs android unit tests in debug/release <br></br> **Options:** `-- --release` |
| `yarn test-snapshot-ios` | runs ios snapshot tests <br></br> **Options:** `-- --release` |
| `yarn test-e2e-ios-ci` | runs the ios e2e tests using [detox](https://github.com/wix/detox) in CI mode (release, multi-device) |
| `yarn test-e2e-android-ci` | runs the android e2e tests using [detox](https://github.com/wix/detox) in CI mode (release, multi-device) |
| `yarn workspace react-native-navigation-playground test-e2e-ios` | runs the ios e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release` |
| `yarn workspace react-native-navigation-playground test-e2e-android` | runs the android e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release` |
| `yarn test-all` | runs all tests in parallel (js, autolink, unit, snapshot, e2e) |

---

### Docs SideMenu Disable (`website/docs/docs/sideMenu-disable.mdx`)

---
id: sideMenu-disable
title: Disable Open and Close gesture
sidebar_label: Open and Close Gesture
---

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Open by pressing on the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button in the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

---

### Docs Stack BackButton (`website/docs/docs/stack-backButton.mdx`)

---
id: stack-backButton
title: The Back button
sidebar_label: Back button
---

The back button is added automatically when two or more screens are pushed into the stack.

## Styling the back button
The back button's style can be customised by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

## Controling visibility
The back buttons visbility can be controlled with the visible property.

```js
backButton: {
  visible: false
}
```

## Changing visbility programmatically
Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false
  }
});
```

## Handling the back button
Handling the back button is not possible. However, you can set a left button with a chevron and handle it like you'd handle any other button and calling `Navigation.pop` when desired.

---

### Docs Stack BackNavigation (`website/docs/docs/stack-backNavigation.mdx`)

---
id: stack-backNavigation
title: Back Navigation
sidebar_label: Back navigation
---

## Disabling back navigation

## Handling back navigation

---

### Docs Stack Buttons (`website/docs/docs/stack-buttons.mdx`)

---
id: stack-buttons
title: TopBar Buttons
sidebar_label: TopBar Buttons
---

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

> When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.

# Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](#showasaction) options to control when the button should appear in the menu.

# Left button

Left buttons behave like right buttons with two caveats on Android:

- Only a single left button is alowed
- Textual left button isn't supported

# Using a react component in a button

> ⚠️At the moment, Android only supports using custom buttons in `rightButtons`.

Sometimes we require more from our buttons. In order to support every product need React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as thier custom view:

```js
topBar: {
  rightButtons: [
    {
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

## Updating props of custom buttons

To update props of a mounted compoennt used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger React's component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0
        },
      },,
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

# Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

## Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

## Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

---

### Docs Stack Programmatically (`website/docs/docs/stack-programmatically.mdx`)

---
id: stack-programmatically
title: Interact programmatically with the Stack
sidebar_label: Interact programmatically
---

The Navigation object provides ways to programmatically manipulate the stack.

## Interact with the Stack by componentId
Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN'
      }
    });
  }
}
```

## Interact with the Stack by a predefined id
Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent'
          }
        }
      ]
    }
  }
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen'
    }
  });
}
```

---

### Docs Style Animations (`website/docs/docs/style-animations.mdx`)

---
id: style-animations
title: Animations
sidebar_label: Animations
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Various UI elements can be animated by declaring animation options.
You can change the default animations for various commands, like push and pop, and even animate elements in
your screens during screen transitions.

#### Animation properties

The following properties can be animated with our animation framework:

- **x** - Translate the view to a coordinate along the x axis.
- **y** - Translate the view to a coordinate along the y axis.
- **translationX** - Translate the view along the x axis relative to its current x position.
- **translationY** - Translate the view along the y axis relative to its current y position.
- **alpha** - Apply alpha animation to the view. A value of 0 means the view is not visible, 1 means it's visible.
- **scaleX** - Scale the view on the x axis. A value of 1 means that no scaling is applied.
- **scaleY** - Scale the view on the y axis. A value of 1 means that no scaling is applied.
- **rotationX** - Applies rotation around the x axis (in degrees, passed as a float).
- **rotationY** - Applies rotation around the y axis (in degrees, passed as a float).
- **rotation** - Rotates the view on all axis. Positive values result in clockwise rotation.

## Layout animations

### Root animations

Animating switches between roots, using the enter/exit animations that grants control on how each root is animated when entering or exiting the screen.

This can be acheived by modifying the default options (`setDefaultOptions` for example) to be like:

```js
options:{
  animations: {
        push:{...},
        setRoot: {
          enter: {
            waitForRender: true,
            enabled: false,
            translationY: {
              from: 0,
              to: 1,
              duration: 3,
            },
          },
          exit:{...}
        },
      },
    };
```
In Playground, you can try it by setting `useCustomAnimations` in `flags.ts` file.

### Stack animations

When animating screens in and out of a stack, there are three elements you can work with:

1. **content** - screen being pushed or popped
2. **topBar** - stack's TopBar
3. **bottomTabs** - if stack is a child of a bottomTabs layout, we can control the `hide` and `show` animations of the bottomTabs.

The following example demonstrates how to replace the default push and pop animations with slide animations.

<Tabs
  defaultValue="push"
  values={[
    { label: 'Push', value: 'push', },
    { label: 'Pop', value: 'pop', },
  ]
}>
<TabItem value="push">

```js
options: {
  animations: {
    push: {
      content: {
        translationX: {
          from: require('react-native').Dimensions.get('window').width,
          to: 0,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
<TabItem value="pop">

```js
options: {
  animations: {
    pop: {
      content: {
        translationX: {
          from: 0,
          to: -require('react-native').Dimensions.get('window').width,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
</Tabs>

### Modal animations

Modal animations are declared similarly to stack animations, only this time we animate the entire view and not only part of the UI (content).
The appearing modal can play custom enter animation and exit for the disappearing screen when showing/dismissing modal.

<Tabs
  defaultValue="show"
  values={[
    { label: 'Show', value: 'show', },
    { label: 'Dismiss', value: 'dismiss', },
  ]
}>
<TabItem value="show">

The following example demonstrates how to show a modal with a fade-in animation.

:::warning Deprecation warning
Consider using enter, exit animations instead.
```js
options: {
  animations: {
    showModal: {
      alpha: {
        from: 0,
        to: 1,
        duration: 300
      }
    }
  }
}
```
:::
```js
options: {
  animations: {
    showModal: {
    enter :{
      enabled:true,
      alpha: {
            from: 0,
            to: 1,
            duration: 300
       }
    },
    exit :{
      enabled:true,
      alpha: {
                from: 1,
                to: 0,
                duration: 300
           }
        }
    }
  }
}
```


</TabItem>
<TabItem value="dismiss">

The following example demonstrates how to dismiss a modal with a fade-out animation.

:::warning Deprecation warning
Consider using enter, exit animations instead.
```js
options: {
  animations: {
    dismissModal: {
      alpha: {
        from: 1,
        to: 0,
        duration: 300
      }
    }
  }
}
```
:::

```js
options: {
  animations: {
    dismissModal: {
     exit:{
     enabled:true
      alpha: {
             from: 1,
             to: 0,
             duration: 300
         }
      },
      enter:{
       enabled:false
       alpha: {
            from: 0,
            to: 1,
            duration: 300
         }
      }
    }
  }
}
```
</TabItem>
</Tabs>

## Shared element transitions

Shared element transitions allow us to provide visual continuity when navigating between destinations. This also focuses user attention on a particular significant element, which then also gives such user better context when transitioning to some other destination.

:::caution
At the moment, the transition is available for push and pop commands. We are working on expanding supported commands to show/dismiss modal and change BottomTabs.
:::

### Transition breakdown

Let's take a more in-depth look at the following example, which you can find in the playground app:

> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx)

<p align="center">
  <img alt="Shared Element Transition" src={useBaseUrl('img/sharedElement.gif')} />
</p>

Four elements are animated in this example. Let's list the elements involved in the transition and note which properties are being animated.

- **image** - the item image is animated to the next screen.

  - image scale (resizeMode)
  - position on screen

- **image background** - each item has a "shadow" view which transitions to the next screen and turns into a colorful header.

  - scale
  - position on screen
  - color

- **title** - the title of the item is animated to the next screen.

  - font size
  - font color
  - position on screen

- **Description** - the description of the item in the destination screen.
  - fade-in
  - translation y

### Implementing shared element transitions

#### Step 1 - set a nativeID prop to elements in the source screen

In order for RNN to be able to detect the corresponding native views of the elements,
each element must include a unique `nativeID` prop.

```jsx
<Image
  source={item.image}
  nativeID={`image${item.id}`}
  style={styles.image}
  resizeMode={'contain'}
/>
```

#### Step 2 - set a nativeID prop to elements in the destination screen

```jsx
<Image source={this.props.image} nativeID={`image${this.props.id}Dest`} style={styles.image} />
```

#### Step 3 - Declare the shared element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          sharedElementTransitions: [
            {
              fromId: `image${item.id}`,
              toId: `image${item.id}Dest`,
              interpolation: { type: 'linear' }
            },
          ],
        },
      },
    },
  },
});
```

The `interpolation` property is an object which consists of a `type` property, and optional parameters to further configure the interpolation function. The following `type`s are supported:

* `'accelerate'`: Begin building up speed until destination has been reached.
  - `factor`: The acceleration factor. Higher values look faster.
* `'decelerate'`: Start at a high speed and slow down to settle.
  - `factor`: The acceleration factor. Higher values look slower.
* `'accelerateDecelerate'`: Begin building up speed until half of the animation is complete, then begin slowing down to settle.
* `'decelerateAccelerate'`: Start at a high speed and slow down until half of the animation is complete, then speed up again to settle.
* `'linear'`: Linearly move towards the destination.
* `'overshoot'`: Begin building up speed and overshoot the destination, then fling back to settle.
  - `tension`: The tension of the overshoot animation defines how far the object can overshoot. _Default: `1`_
* `'spring'`: Acts like an actual spring. Depending on the configuration, this interpolation can overshoot the destination multiple times, or be very stiff and smoothly ease towards the destination.
  - `mass`: The mass defines how "heavy" the object is. _Default: `3`_
  - `damping`: The damping property specifies how much the moving object is being slowed down. Higher values can lead to overdamping, lower values to underdamping. _Default: `500`_
  - `stiffness`: The stiffness property defines how stiff the animated object is. _Default: `200`_

:::caution
Since a Spring interpolation is not a time based animation, you have to manually tweak the configuration to match the duration of the animation, otherwise the remaining time of the Spring interpolation will get skipped.
:::

## Element Transitions

Element transitions also allow you to animate elements during shared element transitions.

### Recreating

#### Step 1 - Set a nativeID prop to the element you'd like to animate

An element can either be in the source or destination screen.

```jsx
<Text nativeID="description" style={styles.description}>
  {this.props.description}
</Text>
```

#### Step 2 - Declare the element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          elementTransitions: [
            {
              id: 'description',
              alpha: {
                from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1
                duration: SHORT_DURATION,
              },
              translationY: {
                from: 16, // Animate translationY from 16dp to 0dp
                duration: SHORT_DURATION,
              },
            },
          ],
        },
      },
    },
  },
});
```

## Peek and Pop (iOS 11.4+)

react-native-navigation supports [Peek and pop](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/#//apple_ref/doc/uid/TP40016543-CH1-SW3) feature in iOS 11.4 and newer.

This works by passing a ref to a component you want to transform into peek view. We have included a handy component to handle all the touches and ref for you:

```jsx
const handlePress ({ reactTag }) => {
  Navigation.push(this.props.componentId, {
    component {
      name: 'previewed.screen',
      options: {
        preview: {
          reactTag,
          height: 300,
          width: 300,
          commit: true,
          actions: [{
            title: "Displayed Name",
            id: "actionId",
            style: 'default', /* or 'selected', 'destructive'*/
            actions: [/*define a submenu of actions with the same options*/]
          }]
        },
      },
    },
  });
};

const Button = (
  <Navigation.TouchablePreview
    touchableComponent={TouchableHighlight}
    onPress={handlePress}
    onPressIn={handlePress}
  >
    <Text>My button</Text>
  </Navigation.TouchablePreview>
);
```

All options except for reactTag are optional. Actions trigger the same event as [navigation button presses](https://wix.github.io/react-native-navigation/#/docs/topBar-buttons?id=handling-button-press-events). To react when a preview is committed, listen to the [previewCompleted](https://wix.github.io/react-native-navigation/#/docs/events?id=previewcompleted-ios-114-only) event.

---

### Docs Style Constants (`website/docs/docs/style-constants.mdx`)

---
id: style-constants
title: Constants
sidebar_label: Constants
---

React Native Navigation exposes a set of constants which can be used to get the dimensions of various navigation elements on the screen: StatusBar, TopBar and BottomTabs.

## When are constants evaluated
Some of the values exposed through the constants API are actually evaluated only after the UI is created (`setRoot` has been called) and therefore are not accessible through static getters.

For example, if you need to get the height of the BottomTabs, you'll first need to have BottomTabs visible on the screen and only then retrieve their height via the constants API.

:::important
We recommend you don't cache the actual constants object returned by `await Navigation.constants()` or `Navigation.constantsSync()` as it might not be accurate later on when, for example, a new root is set or orientation changes.
:::

## API
As explained above, constants are evaluated in native each time the API is invoked. There are two methods for accessing constants:

- `Navigation.constants()`, which is async and thus returns a promise
- `Navigation.constantsSync()`, which returns the constants synchronously, blocking the main thread

Where possible, it is better to use the async method, since this will not block the main thread.

```js
const { Navigation } = require('react-native-navigation');
const {
  statusBarHeight,
  topBarHeight,
  bottomTabsHeight
} = await Navigation.constants();
```

But, if you need to access the constants synchronously (e.g. within the `render()` method of a React component), you can do so as follows:

```js
const { Navigation } = require('react-native-navigation');
const {
  statusBarHeight,
  topBarHeight,
  bottomTabsHeight
} = Navigation.constantsSync();
```

---

### Docs Style Edge To Edge (`website/docs/docs/style-edge-to-edge.mdx`)

---
id: style-edge-to-edge
title: Edge-to-Edge (Android)
sidebar_label: Edge-to-Edge
---

Starting with Android 15 (API 35), the system enforces edge-to-edge display by default — app content draws behind the transparent status bar and navigation bar. React Native Navigation provides built-in support for this behavior, disabled by default.

## Enabling edge-to-edge

To enable edge-to-edge, set `windowOptOutEdgeToEdgeEnforcement` to `false` in your app's theme:

```xml

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:windowOptOutEdgeToEdgeEnforcement">false</item>
    </style>
</resources>
```

`NavigationActivity` reads this attribute on startup. When set to `false` on API 35+, it calls `EdgeToEdge.enable()` to draw content behind system bars. On older API levels this attribute has no effect.

## How it works

When edge-to-edge is active:

- **Status bar and navigation bar** become transparent. React Native Navigation manages view-based background overlays for both, replacing the deprecated `window.statusBarColor` / `window.navigationBarColor` APIs.
- **`SafeAreaView`** receives correct navigation bar insets, so content is automatically inset from the system navigation bar.
- **Bottom tabs** account for navigation bar insets when positioning.
- **Navigation mode detection** — the library detects gesture navigation vs 3-button navigation at runtime and applies appropriate default styling for the navigation bar background.

When edge-to-edge is not active (the default), behavior is unchanged from previous versions.

## Custom behavior

`NavigationActivity.enableEdgeToEdge()` is a `protected` method that controls when edge-to-edge is enabled. Override it in your `MainActivity` to customize the decision logic, and call `activateEdgeToEdge()` to enable it:

```kotlin
class MainActivity : NavigationActivity() {
    override fun enableEdgeToEdge() {
        // Always enable edge-to-edge regardless of theme or API level
        activateEdgeToEdge()
    }
}
```

`activateEdgeToEdge()` handles both the Android system call and the internal navigation framework state. Always use it instead of calling `EdgeToEdge.enable()` directly.

## Styling system bars

Status bar and navigation bar colors can still be controlled per-screen via options:

```js
options: {
  statusBar: {
    backgroundColor: 'white',
    style: 'dark'
  },
  navigationBar: {
    backgroundColor: '#000000'
  }
}
```

Use `navigationBar.drawBehind` with edge-to-edge to draw content behind the system navigation bar while keeping it visible (gesture pill or 3-button bar stay on screen). Layout insets skip the navigation bar height; RNN paints an optional scrim via `backgroundColor`:

```js
// Transparent nav bar — content shows through, pill visible
options: {
  navigationBar: {
    visible: true,
    drawBehind: true,
    backgroundColor: 'transparent'
  }
}

// Opaque scrim over content behind the nav bar
options: {
  navigationBar: {
    visible: true,
    drawBehind: true,
    backgroundColor: '#20303C'
  }
}
```

Without `drawBehind`, an opaque `backgroundColor` reserves bottom inset so content sits above the navigation bar (traditional behavior). See [Navigation Bar options](../api/options-navigationBar) for `visible` and other fields.

These options work in both edge-to-edge and non-edge-to-edge modes. In edge-to-edge mode, the colors are applied to the view-based overlays rather than the deprecated window APIs.

---

### Docs Style Fonts (`website/docs/docs/style-fonts.mdx`)

---
id: style-fonts
title: Changing fonts
sidebar_label: Changing fonts
---

Before you begin using your own fonts, you'll first need to add them to the app project.

* **Android** - add the `.ttf` or `.otf` files to `src/main/assets/fonts/`
* **iOS** - follow this [guide](https://medium.com/react-native-training/react-native-custom-fonts-ccc9aacf9e5e)

Once we've added the font files to our project, we can star using them in options.

:::note
When declaring fonts in options, use only the file name without the file type suffix.
:::

## BottomTab font

```js
options: {
  bottomTab: {
    fontFamily: 'helvetica'
  }
}
```

## Button font

```js
options: {
  rightButtons: [
    {
      id: 'SAVE_BUTTON',
      text: 'Save',
      fontFamily: 'helvetica'
    }
  ],
  leftButtons: [
    {
      id: 'CANCEL_BUTTON',
      text: 'Cancel',
      fontFamily: 'helvetica'
    }
  ]
}
```

## Title font

```js
options: {
  topBar: {
    title: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Subtitle font

```js
options: {
  topBar: {
    subtitle: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Back button

In iOS the back button will display the title of the previous screen. Use the `backButton` option to modify its font family.

```js
options: {
  topBar: {
    backButton: {
      fontFamily: 'helvetica'
    }
  }
}
```

---

### Docs Style Orientation (`website/docs/docs/style-orientation.mdx`)

---
id: style-orientation
title: Orientation
sidebar_label: Orientation
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Locking orientation

Orientation can be locked either in the layout level, or across the app via default options. You can declare orientations you'd like your app to support in default options.

<Tabs
  defaultValue="defaultOptions"
  values={[
    { label: 'Locking orientation in default options', value: 'defaultOptions', },
    { label: 'Locking root layout orientation', value: 'root', },
    { label: 'Showing landscape modal', value: 'modal', }
  ]
}>
<TabItem value="defaultOptions">


Setting orientation in default options will affect all screens in all hierarchy levels. It's still possible to override orientation for specific screens.

```js
Navigation.setDefaultOptions({
  layout: {
    orientation: ['portrait'],
  },
});
```

</TabItem>
<TabItem value="root">


Applying orientation in the root level will affect all screens in the root hierarchy level. It **will not** apply to modals.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      options: {
        layout: {
          orientation: ['portrait']
        }
      },
      children: [
        ...
      ]
    }
  }
});
```

</TabItem>
<TabItem value="modal">


The following example demonstrates how to show a modal in landscape orientation.

```js
Navigation.showModal({
  component: {
    name: 'VideoPlayer'
    options: {
      layout: {
        orientation: ['landscape']
      }
    }
  }
});
```

</TabItem>
</Tabs>


## Changing orientation dynamically

Changing orientation dynamically through `Navigation.mergeOption()` is supported only on Android.

```js
Navigation.mergeOptions(this.props.componentId, {
  layout: {
    orientation: ['landscape'],
  },
});
```

---

### Docs Style Screens (`website/docs/docs/style-screens.mdx`)

---
id: style-options
title: Styling with options
sidebar_label: Options
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

A Screen's look and feel is configured with an [Options](../api/options-root) object. Options can be applied to screens in three ways. Each method of applying options has benefits and draw backs which are important be aware of so we can use the right tool for the job.

## Command options

Options can be passed to layouts as part of a command. For example when pushing a screen. Options passed in commands are typically dynamic options which are determined at runtime.

In the example below we're pushing a user profile screen and we'd like show the user name in the title. To do so, we set the title in the component's options.

```tsx file=./style-screens/command-options.tsx
```

Notice how the title is actually inferred from the `user` object which is set in `passProps`. While this works perfectly fine, declaring the title each time a screen is pushed is a bit tedious and error prone. Later on we'll see a more convenient method to declare dynamic options which are inferred from props.

## Static options

Static options are options that are declared statically **on** the component class. Whenever a screen has a known predefined style, static options should be used as they are evaluated immediately when the screen is created.

<Tabs
  defaultValue="class"
  values={[
    { label: 'Class Component', value: 'class', },
    { label: 'Functional Component', value: 'functional', }
  ]
}>
<TabItem value="class">

```tsx file=./style-screens/static-options-class.tsx
```

</TabItem>
<TabItem value="functional">

```tsx file=./style-screens/static-options-fn.tsx
```

</TabItem>
</Tabs>

### Handle props in static options

Sometimes a screen's style includes properties defined in the calling scope where the screen is used. Like in the user profile screen we've seen above where the the user name is used as the TopBar title. As the user name is unique for each profile, it can't be defined explicitly in the static options.

Luckily, we can access props from static options and set the title from static options! Let's see how this is done:

<Tabs
  defaultValue="class"
  values={[
    { label: 'Class Component', value: 'class', },
    { label: 'Functional Component', value: 'functional', }
  ]
}>
<TabItem value="class">

```tsx file=./style-screens/static-options-props-class.tsx
```

</TabItem>
<TabItem value="functional">

```tsx file=./style-screens/static-options-props-fn.tsx
```

</TabItem>
</Tabs>

Following this approach we can determine options that are dependent on other external factors, such as experiments or A/B tests.

```tsx file=./style-screens/static-options-experiments.tsx
```

## Merge options

The `mergeOptions` command is used to update a layout's style. Keep in mind that the merge happens in native, and not ins JS. This meaning that if `mergeOptions` is called to update a screen's options, the static options declared on the React Component are not affected by mergeOptions.

The following example shows how to update a TopBar background color to red.

```tsx file=./style-screens/merge-options.tsx
```

---

:::warning
**Avoid using mergeOptions in a screen's constructor or in componentDidMount!**
:::

When a screen first appears, it's `constructor` and `componentDidMount` functions are called followed by a `componentDidAppear` event. (read more about screen lifecycle [here](docs-screen-lifecycle.mdx)).

Developers might be tempted to call `mergeOptions` in constructor or componentDidMount to update options. Calling `mergeOptions` before the `componentDidAppear` event has been received has two very negative effects:

1. Updating certain options can trigger additional layout and draw cycles which can have serious impact on performance.
2. Options applied dynamically with the `mergeOptions` command might be handled in native **after** the screen has already appeared. This will result in noticeable flickering and artifacts as options are updated after the initial options have been applied and are visible to the user.

---

### Docs Style Statusbar (`website/docs/docs/style-statusbar.mdx`)

---
id: style-statusBar
title: StatusBar
sidebar_label: StatusBar
---

The StatusBar appearance is controlled through options.

For example, the following options will change the StatusBar background color to white will use dark colors for the StatusBar content (time, battery information, notification icons etc)

```js
options: {
  statusBar: {
    backgroundColor: 'white',
    style: 'dark'
  }
}
```

:::warning Compatibility with StatusBar component
React native's [StatusBar](https://reactnative.dev/docs/statusbar#__docusaurus) component is incompatible with React Native Navigation and you should avoid using it.
:::

## Changing StatusBar style dynamically

As the StatusBar is controlled through options, it can be configured dynamically by calling `Navigation.mergeOptions` with the desired StatusBar options.

For example, here's how you would hide the StatusBar dynamically

```js
Navigation.mergeOptions(this.props.componentId, {
  statusBar: {
    visible: false
  }
});
```

## How to keep current StatusBar color when displaying screens

When screens are displayed, the StatusBar color always changes to the color associated with the current screen. If a color isn't specified for a given screen (and thus for the StatusBar), the default (System default or from defaultOptions) color is used. Sometimes you might want to keep the current StatusBar color, for example when displaying an alert or a toast. To keep StatusBar color unchanged when displaying a screen, use `null` as a StatusBar color.

```js
options: {
  statusBar: {
    backgroundColor: null
  }
}
```

---

### Docs Style Theme (`website/docs/docs/style-theme.mdx`)

---
id: style-theme
title: Themes
sidebar_label: Themes
---

A theme is a type of style which is applied to the entire app. It allows you to declare
a consistent style to all Navigation components such as the TopBar and BottomTabs and also
to system elements like the StatusBar and NavigationBar.
## Dark mode

Dark mode support for navigation UI components can be done via colors, perferably via setting a "Theme" in the default options, as in the example below.

The trigger for the change is the system wide Dark Mode toggle.

```js
Navigation.setDefaultOptions({
  topBar: {
    background: {
      color: {
        light:'white',
        dark:'black'
      }
    },
    title:{
      color: {
        light:'black',
        dark:'red'
      }
    }
  }
});

## Applying a theme

Themes are applied using `Navigation.setDefaultOptions()` which must be called **before** `Navigation.setRoot()` is called.

```js
// Set the default topBar background color to red
Navigation.setDefaultOptions({
  topBar: {
    background: {
      color: 'red'
    }
  }
});

// That stack's topBar background color will be red, as is set in default options
Navigation.setRoot({
  root: {
    stack: {
      children: [
        ...
      ]
    }
  }
});
```

## Conditional themes with Options Processor

Some style requirements can't be facilitated with the `defaultOptions` api. For example, an app may have a unique theme for screens displayed in a modal or require that modals have a default dismiss button in the TopBar. An Options Processor allow us to mutate the options object of each screen and layout right before they are displayed.

Lets see how we can leverage this API to add a dismiss button to the TopBar when showing a modal.

```tsx file=./style-theme/option-processor.tsx
```

The Options Processors can also be used to set default options for buttons, here's how:

```tsx file=./style-theme/option-processor-defaults.tsx
```

## Conditional themes with Layout Processor

Layout Processor is similar in concept to the Options Processor discussed above. While Options Processor is invoked for each options object, Layout Processor is invoked once on the entire (layout)['../api/layout-layout/'] tree passed to the Navigation command.

Through the Layout Processor we can access the layout and it's children, and mutate both options and passProps before the layout is displayed. In this example we iterate on the stack's children and set a dark TopBar color according to a `theme` property in the child's props.

```tsx file=./style-theme/layout-processor.tsx
```

## Changing theme dynamically

Apps can have multiple themes and sometimes you might need to change theme dynamically. To change current theme, simply call `Navigation.setDefaultOptions()` with updated theme options, following that with a call to `Navigation.setRoot()`. The reason we need to setRoot once more is because `Navigation.setDefaultOptions()` does not apply options to screens which had already been created.

---

### Docs Third Party Mobx (`website/docs/docs/third-party-mobx.mdx`)

---
id: third-party-mobx
title: MobX
sidebar_label: MobX
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

MobX is one of the most popular state management libraries used by applications sized from small to large.
With the introduction of the new React Context API, MobX can now be very easily integrated in React Native Navigation
projects.

:::info Note
With the introduction of the new Context API, there is no need to use `Provider` pattern with MobX and you
can now just use the React Context API.

Also the example uses `mobx-react-lite` but you can use the normal `mobx-react`.
:::

## Sharing a store between multiple screens

In the example below we will be creating a small Counter app. We will learn how to integrate Mobx with React-Native-Navigation and demonstrate how updating the store from one component, triggers renders in other components connected to the same store.

Once you finish implementing the example, your screen should look similar to this:

<img width="30%" src={useBaseUrl('/img/mobx_counter.png')} />

### Step 1 - Create a Counter store

Let's first create a counter store using MobX. Our store has a single `count` object and two methods to increment and decrement it.

<Tabs
  defaultValue="makeObservable"
  values={[
    { label: 'MakeObservable', value: 'makeObservable' },
    { label: 'Decorator', value: 'decorator' },
  ]}
>

<TabItem value="makeObservable">

```tsx file=./third-party-mobx/counter-store.tsx 
```

</TabItem>

<TabItem value="decorator">

  From `mobx@6.0.0` decorators have become an opt-in feature. To enable decorators for `mobx`, follow the [official guide](https://mobx.js.org/enabling-decorators.html).

  ```tsx file=./third-party-mobx/counter-store-decorator.tsx 
  ```

</TabItem>

</Tabs>

### Step 2 - Consuming the store

You can consume the Counter store in any React components using `useCounterStore` hook or `React.useContext`

```tsx file=./third-party-mobx/counter-screen.tsx
```

## How to use MobX persistent data

Often the app will require a persistent data solution and with MobX you can use [`mobx-react-persist`](https://github.com/pinqy520/mobx-persist).
It only takes few extra steps to integrate the library. 

Also the integration assumes that you are using the decorator pattern for `mobx`.

```tsx file=./third-party-mobx/persistent-data.tsx
```

---

### Docs Third Party React Context (`website/docs/docs/third-party-react-context.mdx`)

---
id: third-party-react-context
title: React Context API
sidebar_label: React Context API
---

## React Context API 
React Context API provides a easy way to pass data through the component tree without having to pass props down 
manually at every level. You can find more about the Context API in [React documentation](https://reactjs.org/docs/context.html).

You can use the React Context API with React Native Navigation with a limitation. In this example, we are going to create a screen which uses the Counter Context.

:::important Limitation
As RNN screens are not part of the same component tree, updating the values in the shared context does not trigger a re-render across all screens.
However you can still use the React.Context per RNN screen component tree.

If you need to trigger a re-render across all screens, there are many popular third party libraries such as 
[MobX](third-party-mobx.mdx) or Redux.
:::

## Create a Counter context

```tsx file=./third-party-react-context/CounterContext.tsx
```

## Register the screen
When registering the screen that will be using the Counter Context, we need to wrap it
with the Counter Context Provider we created earlier.

```tsx file=./third-party-react-context/index.tsx
```

## Consuming the context
You can consume the Counter Context any way you want such as `Provider.Consumer` or `React.useContext` like in the 
example below.

```tsx file=./third-party-react-context/App.tsx
```

```tsx file=./third-party-react-context/App-consumer.tsx
```

---

### Docs Third Party React Native Vector Icons (`website/docs/docs/third-party-react-native-vector-icons.mdx`)

---
id: third-party-react-native-vector-icons
title: react-native-vector-icons
sidebar_label: react-native-vector-icons
---

react-native-vector-icons is a very popular library for using SVG icons in react-native, which keeps large static images
out of your app while providing crisp icons. Using this library with React Native Navigation is not difficult, but does take
a few extra steps..

## Using SVG icons in BottomTabs or TopBarButtons

In the example below we will detail a simple app that pre-loads several icons from react-native-vector-icons to be used in our navigation. The example assumes
you have worked through the [installation](https://github.com/oblador/react-native-vector-icons#installation) and optional steps to support [custom fonts](https://github.com/oblador/react-native-vector-icons#custom-fonts)
according to the react-native-vector-icons project.

### Step 1 - Choose icons and load image source.

The core issue here is that React Native Navigation wants 'images' for its icons while react-native-vector-icon typically works as a component. However,
there is a way around this, by using the `getImageSourceSync` method exposed by react-native-vector-icons.

You can use this directly when specifying an `icon` in an react-native-navigation option, or you can group them all together into a central object like so:

```tsx file=./third-party-react-native-vector-icons/NavIcons.tsx
```

### Step 2 - Launching the app.

We now launch our app in the usual fashion.

```tsx file=./third-party-react-native-vector-icons/index.ts
```

### Step 3 - Using NavIcons in components.

One of the nice features of React Native Navigation is that it is possible to specify the navigation 'options' on each individual component. This still works with NavIcons
framework we have setup:


```tsx file=./third-party-react-native-vector-icons/ExampleComponent.tsx
```

---

### Docs Third Party Typescript (`website/docs/docs/third-party-typescript.mdx`)

---
id: third-party-typescript
title: TypeScript
sidebar_label: TypeScript
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Strongly typed components

Both functional and class components can be typed to get the benefits of strongly typed options and props.

<Tabs
  defaultValue="clazz"
  values={[
    { label: 'Class Component', value: 'clazz' },
    { label: 'Functional Component', value: 'functional' },
  ]}
>

<TabItem value="clazz">

```tsx file=./third-party-typescript/strongly-typed-components-class.tsx
```

</TabItem>

<TabItem value="functional">

```tsx file=./third-party-typescript/strongly-typed-components-fn.tsx
```

</TabItem>

</Tabs>

## Typed props in commands

Arguments are passed to components view the `passProp`. This is a common source for errors as these props tend to change overtime. Luckily we can type the passProps property to avoid these regressions. The example below shows how to declare types for passProps when pushing a screen.

```tsx file=./third-party-typescript/typed-props-in-commands.tsx
```

The following commands accept typed passProps:

- push
- setStackRoot
- showModal
- showOverlay

---

### Website Versioned Docs Version 6.12.2 Docs Community Libraries (`website/versioned_docs/version-6.12.2/docs/community-libraries.mdx`)

---
id: community-libraries
title: Community libraries
sidebar_label: Community libraries
---

React Native Navigation has an active community with a bunch of support libraries.

[React Native Navigation Hooks](https://github.com/underscopeio/react-native-navigation-hooks) :
A set of React hooks for React Native Navigation.

[React Native Navigation Drawer Extension](https://github.com/lukebrandonfarrell/react-native-navigation-drawer-extension) :
Drawer API built on top of React Native Navigation for iOS and Android. 

[React Native Navigation Search Bar](https://github.com/lukebrandonfarrell/react-native-navigation-search-bar) :
React Native Elements search bar with collapsible header built for React Native Navigation.

[React Native Navigation Register Screens](https://github.com/karlmarxlopez/react-native-navigation-register-screens) : 
Utility function to register array of screens instead of calling `Navigation.registerComponent` multiple times.

---

### Website Versioned Docs Version 6.12.2 Docs Docs Installing (`website/versioned_docs/version-6.12.2/docs/docs-Installing.mdx`)

---
id: installing
title: Installation
sidebar_label: Installation
---

## Requirements
* node >= 8
* react-native >= 0.51

## npm or yarn
* `npm install --save react-native-navigation`

...or if you use `yarn`:

* `yarn add react-native-navigation`

## Installing with `npx rnn-link`
If you're using RN 0.60 or higher, you can benefit from autolinking for some of the necessary installation steps. But unlike most other libraries, react-native-navigation requires you to make a few changes to native files.

We've simplified the process through a set of scripts. So to make all the necessary changes automatically, in your project's root folder run:

```npx rnn-link```

Make sure to commit the changes introduced by the `rnn-link` script.

> The automatic linking is optimized for new applications created via the `react-native init` command. If you are migrating from a version of react-native-navigation older than v5, it's recommended to check the steps manually after the script runs.

If the link script completed successfully, you're good to go! No more native configuration is required.

If one of the steps failed or you can't run (or are not comfortable with) the automatic scripts, you'll need to complete the relevant steps in the manual installation steps below, for both platforms.

## Displaying the app root

### Update index.js file
`index.js` is typically used as an entry point into the app. It's first parsed and executed by the JS engine, therefore we'll want to show our UI from there.

The following diff demonstrates changes needed to be made to `index.js`, initialized by `react-native init`.

```diff
+import { Navigation } from "react-native-navigation";
-import {AppRegistry} from 'react-native';
import App from "./App";
-import {name as appName} from './app.json';

-AppRegistry.registerComponent(appName, () => App);
+Navigation.registerComponent('com.myApp.WelcomeScreen', () => App);

+Navigation.events().registerAppLaunchedListener(() => {
+   Navigation.setRoot({
+     root: {
+       stack: {
+         children: [
+           {
+             component: {
+               name: 'com.myApp.WelcomeScreen'
+             }
+           }  
+         ]
+       }
+     }
+  });
+});
```

If you followed the steps successfully up to this point, then this should be all! 

:::tip
This is a good moment to build your application in both platforms, validate that everything is working properly and commit your changes. If you're coming from a fresh `react-native init` project, then you should be seeing the Welcome screen as usual, but under the hood your application is using react-native-navigation!
::::

___

## Manual Installation
If installation with `npx rnn-link` did not work, follow the manual installation steps below.

### iOS

> Make sure your Xcode is updated. We recommend editing `.h` and `.m` files in Xcode as the IDE will usually point out common errors.

#### Installation with CocoaPods

Projects generated using newer versions of react-native use CocoaPods by default. In that case it's easier to install react-native-navigation using CocoaPods.

1. Update your `Podfile`:
**If you're upgrading to v5 from a previous RNN version**, make sure to remove manual linking of RNN

```
/* Detailed source-code truncated for AI context efficiency. */
```

2. `cd ios && pod install`

#### Native Installation

> If the React Native version in your project is above 0.60 and you are following the manual installation, skip to step 3. 

If autolinking is not available in your project (RN version < 0.60), you can always try and install the hardcore way:

1. In Xcode, in Project Navigator (left pane), right-click on the `Libraries` > `Add files to [project name]`. Add `node_modules/react-native-navigation/lib/ios/ReactNativeNavigation.xcodeproj` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking)).

2. In Xcode, in Project Navigator (left pane), click on your project (top), then click on your *target* row (on the "project and targets list", which is on the left column of the right pane) and select the `Build Phases` tab (right pane). In the `Link Binary With Libraries` section add `libReactNativeNavigation.a` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-2)).

  a. If you're seeing an error message in Xcode such as:
  ```
  'ReactNativeNavigation/ReactNativeNavigation.h' file not found.
  ```
  You may also need to add a Header Search Path: ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-3)).
  ```objectivec
  $(SRCROOT)/../node_modules/react-native-navigation/lib/ios
  ```

3. In Xcode, you will need to edit this file: `AppDelegate.m`. This function is the main entry point for your app:

  ```objectivec
   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... }
  ```

  Its content should look like this:

  ```objectivec
  #import "AppDelegate.h"

  #import <React/RCTBundleURLProvider.h>
  #import <React/RCTRootView.h>
  #import <ReactNativeNavigation/ReactNativeNavigation.h>

  @implementation AppDelegate

  -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
    [ReactNativeNavigation bootstrapWithDelegate:self launchOptions:launchOptions];
    
    return YES;
  }

  -(NSURL *)sourceURLForBridge:(RCTBridge *)bridge
  {
    #if DEBUG
      return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
    #else
      return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    #endif
  }

  @end
  ```

    a. If, in Xcode, you see the following error message in `AppDelegate.m` next to `#import "RCTBundleURLProvider.h"`: 
    ```
    ! 'RCTBundleURLProvider.h' file not found
    ```
    This is because the `React` scheme is missing from your project. You can verify this by opening the `Product` menu and the `Scheme` submenu. 
    To make the `React` scheme available to your project, run `npm install react-native-git-upgrade` followed by `react-native-git-upgrade`. Once this is done, you can click back to the menu in Xcode: `Product -> Scheme -> Manage Schemes`, then click '+' to add a new scheme. From the `Target` menu, select "React", and click the checkbox to make the scheme `shared`. This should make the error disappear.


### Android

> Make sure your Android Studio installation is up to date. We recommend editing `gradle` and `java` files in Android Studio as the IDE will suggest fixes and point out errors, this way you avoid most common pitfalls.

#### 1 Update `android/build.gradle`:

```diff
buildscript {
  ext {
-   minSdkVersion = 16
+   minSdkVersion = 19 // Or higher
    compileSdkVersion = 26
    targetSdkVersion = 26
    supportLibVersion = "26.1.0"
+   kotlinVersion = "1.3.72" // Or any version above 1.3.x
+   RNNKotlinVersion = kotlinVersion
  }
  repositories {
        google()
        jcenter()
+        mavenLocal()
+        mavenCentral()
  }
  dependencies {
+        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
+        classpath 'com.android.tools.build:gradle:3.5.3' // Or higher
-        classpath 'com.android.tools.build:gradle:2.2.3'
  }
}

allprojects {
  repositories {
+   google()
    mavenLocal()
    jcenter()
    maven {
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
      url "$rootDir/../node_modules/react-native/android"
    }
-        maven {
-            url 'https://maven.google.com/'
-            name 'Google'
-        }
+   maven { url 'https://jitpack.io' }
  }
}
```
#### 2 Update `MainActivity.java`

`MainActivity.java` should extend `com.reactnativenavigation.NavigationActivity` instead of `ReactActivity`.

This file is located in `android/app/src/main/java/com/<yourproject>/MainActivity.java`.

```diff
-import com.facebook.react.ReactActivity;
+import com.reactnativenavigation.NavigationActivity;

-public class MainActivity extends ReactActivity {
+public class MainActivity extends NavigationActivity {
-    @Override
-    protected String getMainComponentName() {
-        return "yourproject";
-    }
}
```

If you have any **react-native** related methods, you can safely delete them.

#### 3 Update `MainApplication.java`

This file is located in `android/app/src/main/java/com/<yourproject>/MainApplication.java`.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### App root

Now that you're done, don't forget to update the `index.js` file, as [shown above](#update-indexjs-file).

## Troubleshooting
### Build app with gradle command
**prefered solution** - The RNN flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .

```
"scripts": {
  ...
  "android": "cd ./android && ./gradlew app:assembleDebug && ./gradlew installDebug"
}
```

Now run `npm run android` to build your application

### Force the same support library version across all dependencies
Some of your dependencies might require a different version of one of Google's support library packages. This results in compilation errors similar to this:

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:preDebugBuild'.
> Android dependency 'com.android.support:design' has different version for the compile (25.4.0) and runtime (26.1.0) classpath. You should manually set the same version via DependencyResolution
```

To resolve these conflicts, add the following to your `app/build.gradle`:

```groovy
android {
    ...
}

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support' && requested.name != 'multidex') {
            details.useVersion "${rootProject.ext.supportLibVersion}"
        }
    }
}

dependencies {
    ...
    implementation 'com.android.support:design:25.4.0'
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
}

```

---

### Website Versioned Docs Version 6.12.2 Docs Docs Advanced Navigation (`website/versioned_docs/version-6.12.2/docs/docs-advanced-navigation.mdx`)

---
id: advanced-navigation
title: Advanced navigation
sidebar_label: Advanced navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

## Tab navigation

As mobile applications become bigger and more complex, they usually end up containing multiple primary high-level destinations, which are logically independent from one another. The `BottomTabs` layout is often used when an app contains three to five top-level destinations which should be accessible from anywhere in the app.

Lets return to the example code from the previous section ([Basic navigation](basic-navigation)) and see how we can convert it to a tab-based application. We'll use the BottomTabs layout to display tabs at the bottom of the screen. Similarly to `Stack` layout, The BottomTabs layout also contains a `children` property where each child will be displayed in a tab.

Lets change our code to the following and reload the app.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Now our app has two tabs at the bottom of the screen and our users can easily navigate between them.

<img width="40%" src={useBaseUrl('img/stack4.png')} />

## Replacing the root

Up until now, we've discussed how to navigate within the same layout structure. We'll now learn how to replace the entire layout structure to display a new Root. A real life example for this use case would be, for instance, if you need to switch from a login screen to the app's main root. Replacing the root fits this use case since we'd like to discard the previous root (login root) entirely when switching to the main root.

To demonstrate this, we'll make the following changes to our code:

1. Add a login screen with a login button.
2. When the button is clicked, we will switch to the main root.
3. Replace our current root with the login screen. We'll also extract both roots to variables to improve code readability.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Conditional roots

Now that our initial root is the Login root, we're facing a new problem - how do we show the Login root only to users that are not logged in? Since our initial root is determined in the `registerAppLaunchedListener` callback, we'll check if a user is logged in there and set the appropriate root accordingly.

```jsx
Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot(isLoggedIn() ? mainRoot : loginRoot);
});

function isLoggedIn() {
  // TODO: your business logic goes here
}
```

---

### Website Versioned Docs Version 6.12.2 Docs Docs App Launch (`website/versioned_docs/version-6.12.2/docs/docs-app-launch.mdx`)

---
id: app-launch
title: Launching the app
sidebar_label: Launching the app
---

When your app is launched for the first time, the bundle is parsed and executed. At this point you need to display your UI. To do so, listen to the `appLaunched` event and call `Navigation.setRoot` when that event is received.

```js
Navigation.events().registerAppLaunchedListener(() => {
  // Each time the event is received you should call Navigation.setRoot
});
```

:::important
Register the app launched listener as soon as possible - this should be one of the first lines in your `index.js` file.
:::

If you're observing a "white screen" or a hanging splash screen after relaunching your app, it probably means `Navigation.setRoot` isn't called as soon as the app is launched. Perhaps the listener was registered too late.

## Difference between the platforms
When your app is launched, RN makes sure JS context (which is what enables you to execute JavaScript code) is running. There are quite a few differences between iOS and Android in this regard.

### iOS
Whenever an app is put into the background, the app process can potentially be destroyed by the system. If this destruction takes place, the JS context will be destroyed alongside with the app process.

### Android
An Android application is typically bound to two contexts:

1. Application context - bound to the app process
1. Activity context - bound to app UI

React's JS Context is executed on and bound to the Application context. This means that even when the Activity context (and thus the UI) is destroyed, React's JS Context remains active until the Application (and your process) are destroyed by the system.

:::caution
Because of this, when your app returns to foreground, JS Context might still exist on Android, even when the Activity and UI contexts have been destroyed - meaning you might not need to initialise all of your app logic; instead, you'll only need to call `Navigation.setRoot` to repopulate the UI context. This circumstance can easily be determined by setting a flag on your app's first `appLaunched` event, and checking the value of that flag on subsequent `appLaunched` events -- if the flag is true in your `appLaunched` callback, you need to call `Navigation.setRoot` to repopulate the UI.
:::

---

### Website Versioned Docs Version 6.12.2 Docs Docs Basic Navigation (`website/versioned_docs/version-6.12.2/docs/docs-basic-navigation.mdx`)

---
id: basic-navigation
title: Basic navigation
sidebar_label: Basic navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

Generally, any mobile app consists of various destinations which display some content to the user. And in vast majority of cases using an app means navigating between these destinations. React-native-navigation provides ways for you to layout your content on user screen in a logical and performant manner.

React Native Navigation's stack layout lets you push screens, and also navigate back to previous screens. Screens pushed into the stack hide the previous screen in the stack, making the user focus on a single screen at a time. Let's look at a stack layout that provides basic navigation for an app.

## Creating a stack

```jsx
// In index.js of a new project
const { Navigation } = require('react-native-navigation');
const React = require('react');
const { View, Text, StyleSheet } = require('react-native');

const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Home Screen</Text>
    </View>
  );
};
Navigation.registerComponent('Home', () => HomeScreen);

Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot({
    root: {
      stack: {
        children: [
          {
            component: {
              name: 'Home'
            }
          }
        ]
      }
    }
  });
});

const styles = StyleSheet.create({
  root: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'whitesmoke'
  }
});
```

Running this code will render a screen with an empty TopBar and your HomeScreen component (shown below). The TopBar is part of the stack layout, we'll work on configuring it later.

<img width="40%" src={useBaseUrl('img/stack1.png')} />

## Specifying options

You can specify options of each layout (Stack, component pushed into a stack, etc.) to configure various parameters like the TopBar title or color. Lets spice things up by changing the TopBar color and while we're at it, also move the title to the TopBar.

Lets change the Home screen declaration to the following and reload the app to see the changes.
```jsx
const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Hello React Native Navigation 👋</Text>
    </View>
  );
};
HomeScreen.options = {
  topBar: {
    title: {
      text: 'Home',
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
}
```

Our app should now look like this:
<img width="40%" src={useBaseUrl('img/stackOptions.png')} />

## Navigating in a stack

In the previous section we created a stack and initialized it with a single child. We'll now learn how to add another child to the stack. From now on, we'll call the action of adding children to the stack 'push', and removing children - 'pop'.

In order to push another screen to the stack, we will add a button to the home screen and call `Navigation.push`. The 'push' command accepts two parameters, the first is the id used to indicate into which stack to push the screen and the second is the screen we're pushing. After pushing a screen, a back button is added automatically to the TopBar so the users can navigate easily back to the previous screen.

You can read more about the stack layout [here](docs-stack.mdx) or dive right into the API [here](../api/layout-stack).

:::info componentId
Each React component registered with `Navigation.registerComponent` is assigned a unique `componentId` by Navigation. This unique id is used with Navigation commands (like the push command) to indicate into which stack we'd like to push. In this case, by using the componentId of the Home screen, we are telling Navigation to push into the stack containing the Home screen.
:::

```js
Navigation.push(props.componentId, {
  component: {
    name: 'Settings', // Push the screen registered with the 'Settings' key
    options: { // Optional options object to configure the screen
      topBar: {
        title: {
          text: 'Settings' // Set the TopBar title of the new Screen
        }
      }
    }
  }
});
```

Lets change our code to the following snippet below and reload the app. Now our Home should contain a button which when pressed, pushes a new screen into the stack. We've successfully navigated to a new screen! 👏

```
/* Detailed source-code truncated for AI context efficiency. */
```

<img width="40%" src={useBaseUrl('img/stack2.gif')} />

## App theme

Our app is growing and already contains two screens. This introduces a new problem - while the home screen has a nice purple TopBar, our settings screen seems pretty dull as it still uses the default system look and feel.

Currently, our style declaration applies only to the Home screen, so lets apply it to all of our screens by using `Navigation.setDefaultOptions`.

```js
Navigation.setDefaultOptions({
  statusBar: {
    backgroundColor: '#4d089a'
  },
  topBar: {
    title: {
      color: 'white'
    },
    backButton: {
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
});
```

We need to add this snippet before registering the `registerAppLaunchedListener`. This way we ensure our theme is applied when our root is set. Our code should now look like this:

```
/* Detailed source-code truncated for AI context efficiency. */
```

Lets run our code again - now our design is consistent across both screens.

<img width="40%" src={useBaseUrl('img/stack3.gif')} />

## Summary

We've learned the basics of navigation with React Native Navigation by implementing a stack and pushing screens into it.
We've also learned a few methods of applying styles to our screens and layouts with the Options mechanism.

* Navigation.setRoot() sets the root layout of our app. The initial root has to be set from an `AppLaunchedEvent` callback.
* Options can be applied directly to components.
* Screens can be added to a stack with the `Navigation.push()` command.
* Components registered with `Navigation.registerComponent()` are injected with a `componentId` which is used when navigating.
* Themes are applied via the `Navigation.setDefaultOptions()` command.

In the next section we'll explore a more advance navigation patterns using BottomTabs layout and also see how, and why, multiple roots are set.

---

### Website Versioned Docs Version 6.12.2 Docs Docs Before You Start (`website/versioned_docs/version-6.12.2/docs/docs-before-you-start.mdx`)

---
id: before-you-start
title: Before you start
sidebar_label: Before you start
---

React Native Navigation is a module, dependent on and intended to be used alongside [React Native](https://github.com/facebook/react-native), so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their [getting started](https://reactnative.dev/docs/getting-started) tutorial, and then come back here when you're ready.

We also assume you are working on a Mac with XCode and Android Studio installed and setup. You can also make it work in a Linux distribution, of course, but in that case bear in mind that some sections of the docs that deal with iOS might not be relevant to you.

If you want to dig right into it, start with [installing](docs-Installing.mdx) the library. If you're just looking around, we suggest checking out [basic navigation](docs-basic-navigation.mdx) first.

---

### Website Versioned Docs Version 6.12.2 Docs Docs BottomTabs (`website/versioned_docs/version-6.12.2/docs/docs-bottomTabs.mdx`)

---
id: bottomTabs
title: Bottom tabs
sidebar_label: Bottom tabs
---
import useBaseUrl from '@docusaurus/useBaseUrl';

Bottom tabs refers to a row of links, displayed at the bottom of the screen, and is referred to as "Tab Bar" in iOS and as "Bottom Navigation Bar" on Android. Usually these are intended to be used to switch between top-level content views with a single tap.

## Creating bottom tabs

BottomTabs provide flat navigation and access to up to five equally important top-level root destinations. While any type of layout can be displayed in a tab, typically, [Stacks](stack) are used, since they allow for vertical navigation within a tab.

### Example
Lets see how to create a simple BottomTabs layout. There are a few things to notice here:
1. Each child represents a tab on the screen.
2. The root layout for each tab is a stack to allow for vertical navigation within the tab.
3. Each stack declares `bottomTab` options which are used to configure the tab's text, icon, color etc.

```js
bottomTabs: {
  id: 'BOTTOM_TABS_LAYOUT',
  children: [
    {
      stack: {
        id: 'HOME_TAB',
        children: [
          {
            component: {
              id: 'HOME_SCREEN',
              name: 'HomeScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./home.png')
          }
        }
      }
    },
    {
      stack: {
        id: 'PROFILE_TAB',
        children: [
          {
            component: {
              id: 'PROFILE_SCREEN',
              name: 'ProfileScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./profile.png')
          }
        }
      }
    }
  ]
}
```

Once we run this code, our BottomTabs should look like this:
<img width="40%" src={useBaseUrl('img/bottomTabs.png')} />

## Selecting Tabs Programmatically
Tabs can be selected programmatically by updating the `currentTabIndex` or `currentTabId` options.

We'll use the BottomTabs layout showcased [above](bottomTabs#example) to demonstrate programmatic tab selection.

### Selecting a tab by index
The following mergeOptions command will select the second tab. We're passing the id of our BottomTabs layout, but we could also use the id of any of the child components, for example `PROFILE_TAB` or `PROFILE_SCREEN`.

```js
Navigation.mergeOptions('BOTTOM_TABS_LAYOUT', {
  bottomTabs: {
    currentTabIndex: 1
  }
});
```

### Selecting a tab by id
Tabs can also be selected by id (`componentId`). This is particularly useful in cases where you don't know in which tab a screen is contained.
For example, if invoked from one of the child components, `HOME_SCREEN` or `SETTINGS_SCREEN`, the following merge command will select the tab containing the child.

```js
Navigation.mergeOptions(this.props.componentId, {
  bottomTabs: {
    currentTabId: this.props.componentId
  }
});
```

## Changing BottomTabs visibility

The `visible` property is used to control the BottomTab visibility. Visibility can be toggled dynamically using the `mergeOptions` command.
```js
Navigation.mergeOptions(componentId, {
  bottomTabs: {
    visible: false
  },
});
```

Visibility can also be changed when pushing screens.
```js
Navigation.push(componentId, {
  component: {
    name: 'pushedScreen',
    options: {
      bottomTabs: {
        visible: false
      }
    }
  }
});
```

## Updating tab options dynamically

To update a tab option, like an icon, text or color, simply call `mergeOptions` with new options using the id of a component or layout contained in the tab you wish to update.

For instance, in the example below we update the color of a specific tab:
```js
Navigation.mergeOptions(componentId, {
  bottomTab: {
    iconColor: 'red',
    textColor: 'red'
  },
});
```

## Controlling tab loading

By default, all tabs are mounted at the same time. This can have a negative impact on performance since screens which are not visible to the user are mounted.

The order in which tabs are mounted can be configured with the `tabsAttachMode` option:

* `together` - all tabs are mounted at the same time, this is the default behavior.
* `afterInitialTab` - after initial tab is mounted, other tabs are mounted.
* `onSwitchToTab` - initial tab is mounted, other tabs are mounted when the user navigates to them for the first time.

---

### Website Versioned Docs Version 6.12.2 Docs Docs ExternalComponent (`website/versioned_docs/version-6.12.2/docs/docs-externalComponent.mdx`)

---
id: externalComponent
title: External Component
sidebar_label: External Component
---

The ExternalComponent layout allows you to display any native view as a screen. To use the External Component we'll need to register it with a string name. This name is then used when declaring layouts in JS.

## Android
### Implementing the native component
When it comes to implementing an external component on Android, you have two choices. We recommend you use a base class extending `View`. If you're required to use Fragments, you'll find an basic example below.

#### ViewGroup
```java
public class ViewGroupComponent implements ExternalComponent {
    private final FrameLayout content;

    ViewGroupComponent(FragmentActivity activity, JSONObject props) {
        content = new FrameLayout(activity);
    }

    @Override
    public View asView() {
        return content;
    }
}
```

#### Fragment

Using a Fragment as an external component is done by attaching the Fragment to a FrameLayout, and returning the FrameLayout from the `asView()` method of the ExternalComponent.

```java
public class FragmentComponent implements ExternalComponent {
    private final FrameLayout content;

    FragmentComponent(FragmentActivity activity, JSONObject props) {
        // Create the FrameLayout to which we'll attach our Fragment to
        content = new FrameLayout(activity);
        content.setId(R.id.fragment_screen_content);
        // Attach the Fragment to the FrameLayout
        activity.getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_screen_content, createFragment(props))
                .commitAllowingStateLoss();
    }

    private FragmentScreen createFragment(JSONObject props) {
        FragmentScreen fragment = new FragmentScreen();
        // Pass the props sent from Js in a bundle
        Bundle args = new Bundle();
        args.putString("text", props.optString("text", ""));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View asView() {
        return content;
    }
}
```

### Registering the component
```java
public class MainApplication extends NavigationApplication {
  @Override
    public void onCreate() {
        super.onCreate();
        registerExternalComponent("MyExternalComponent", new FragmentCreator());
    }
}
```

## iOS
### ViewController registration

```objectivec
[ReactNativeNavigation registerExternalComponent:@"MyExternalComponent" callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
	return [[ExternalViewController alloc] initWithProps:props];
}];

```
## Using the component from JS
Once you've registered the external component in native, you can use it in your layout declarations.
For example, to show an external component modally:
```js
Navigation.showModal({
  externalComponent: {
    name: 'MyExternalComponent',
    passProps: {
      text: "Text from JS"
    }
  }
});
```

:::caution
props passed to external components are sent over the bridge and therefore must be serializable.
:::

---

### Website Versioned Docs Version 6.12.2 Docs Docs Functional Components (`website/versioned_docs/version-6.12.2/docs/docs-functional-components.mdx`)

---
id: functionalComponents
title: Using functional components as screens
sidebar_label: Using functional components
---

Both class components and functional components can be used as screens. There is no performance difference between the two. Deciding which type component to use boils down to user preference.

## Declaring static options
Static options are a great way to declare options close to where they are used. Declaring static options is done by first declaring the functional component, and then declaring the options on the function component.
```jsx
const MyScreen = (props) => {
  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
};

MyScreen.options = {
  topBar: {
    background: {
      color: 'red'
    }
  }
}
```

## Listening to navigation events
Navigation events let you react to various events related to a specific component or the app itself. Read more about them [here](/react-native-navigation/api/events)

```jsx
import { useEffect } from 'react';
import Navigation from 'react-native-navigation';

function MyScreen(props) {
  useEffect(() => {
    const listener = {
      componentDidAppear: () => {
        console.log('RNN', `componentDidAppear`);
      },
      componentDidDisappear: () => {
        console.log('RNN', `componentDidDisappear`);
      }
    };
    // Register the listener to all events related to our component
    const unsubscribe = Navigation.events().registerComponentListener(listener, props.componentId);
    return () => {
      // Make sure to unregister the listener during cleanup
      unsubscribe.remove();
    };
  }, []);

  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
}
```

In the example above, our listener is registered with the `componentId` passed in the second argument, and will receive only its related events.

:::tip
[underscopeio/react-native-navigation-hooks](https://github.com/underscopeio/react-native-navigation-hooks) is a wonderful library which greatly simplifies usage with hooks by introducing dedicated hooks for each event. The following example, which is taken from their docs, shows how to listen to all appear events and a particular screen's appear events:

```jsx
import { useNavigationComponentDidAppear } from 'react-native-navigation-hooks'

const ScreenComponent = ({ componentId }) => {
  // Global listener
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} (${e.componentId}) appeared`)
  })

  // Listen events only for this screen (componentId)
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} appeared`)
  }, componentId)

  return (
    <View>
      <Text>Screen Component</Text>
    </View>
  )
}
```
:::

---

### Website Versioned Docs Version 6.12.2 Docs Docs Modal (`website/versioned_docs/version-6.12.2/docs/docs-modal.mdx`)

---
id: modal
title: Modal
sidebar_label: Modal
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

In human-centered design, when we speak about a modal (or modality), we often refer to a set of techniques, aimed at bringing user attention to a specific event / screen / action / etc. Those often require user input. A pop-up on a website, a file deletion confirmation dialogue on your computer, or an alert asking you to enable location service on your phone - these can all be considered modals.

A modal is a term used in native iOS world ([full description here](https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/)), while on Android, [dialogs](https://developer.android.com/guide/topics/ui/dialogs) are often used to create similar or identical behavior, alongside other techniques.

## Presenting modals

Modal can be displayed by invoking the `Navigation.showModal()` command, as shown in the example below:

```js
Navigation.showModal({
  stack: {
    children: [
      {
        component: {
          name: 'MODAL_SCREEN',
          options: {
            topBar: {
              title: {
                text: 'Modal',
              },
            },
          },
        },
      },
    ],
  },
});
```

Here's how the Modal looks on both platforms.

<Tabs
  defaultValue="ios"
  values={[
    { label: 'iOS', value: 'ios' },
    { label: 'Android', value: 'android' },
  ]}
>
  <TabItem value="ios">
    <img width="40%" src={useBaseUrl('img/modal_ios.gif')} />
  </TabItem>
  <TabItem value="android">
    <img width="40%" src={useBaseUrl('img/modal_android.gif')} />
  </TabItem>
</Tabs>

## Adding a dismiss button

Modals should always have a dismiss button, on left-to-right devices it's typically placed as a left button in the TopBar.

After we've added our dismiss button, we need to dismiss the modal when the button is pressed.

:::note
For the LeftButton to be visible, the screen must be displayed in a Stack.
:::

```js
class ModalScreen extends React.Component {
  // Set a dismiss button in static options
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'dismiss',
          icon: require('./dismiss.png'),
        },
      },
    };
  }

  constructor(props) {
    super(props);
    // Register to events
    Navigation.events().bindComponent(this);
  }

  // Handle the button press event and dismiss the modal if needed
  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'dismiss') {
      Navigation.dismissModal(this.props.componentId);
    }
  }
}
```

## Transparent modals

Showing transparent modals is a nice technique to increase immersiveness while keeping the user in the same context.
When a modal is displayed the content behind it (either root or modal) is removed from hierarchy. While this behavior improves performance, it's undesired when
showing transparent modals as we need to see the content behind it.

To configure this behaviour, we'll need to change the `modalPresentationStyle` option to `overCurrentContext` and change the layout background color to `'transparent'`.

```js
{
  modalPresentationStyle: 'overCurrentContext',
  layout: {
    backgroundColor: 'transparent'
  }
}
```

## Preventing a Modal from being dismissed

Preventing a modal from being dismissed is done differently for each platform. While preventing the user from dismissing the modal is possible,
the modal could still be dismissed programmatically by calling `Navigation.dismissModal()`

If the modal has a dismiss button, of course you'll need to handle it your self and avoid calling `Navigation.dismissModal()`
when the button is pressed.

### Android

On Android, modals can be dismissed with the hardware back button. You can handle the back press your self by
adding a [BackHandler](https://facebook.github.io/react-native/docs/backhandler)

### iOS

While iOS devices don't have a hardware back button, PageSheet modals can be dismissed by swipe gesture
from the top of the screen. To disable it, set [swipeToDismiss](#) option to false.

## Presentation Style

The [presentation style](/react-native-navigation/api/options-root#modalpresentationstyle) determines the look and feel of a screen displayed as modal.

---

### Website Versioned Docs Version 6.12.2 Docs Docs Overlay (`website/versioned_docs/version-6.12.2/docs/docs-overlay.mdx`)

---
id: overlay
title: Overlay
sidebar_label: Overlay
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Overlays are used to layout content on top of all other layout hierarchies, while fitting the screen bounds.
The contents displayed in an Overlay can either be non-obtrusive, like Toasts and Snackbars, or an Alert that blocks all interactions with any content behind it. The view contained within it should be aligned either with absolute position, flex, or with margins, all according to your needs.

## Handling touch events outside the view

When showing views like Alert or Toast in an Overlay, you would want to configure if you want to allow users to interact with content behind the alert. This is done via the [interceptTouchOutside](#) option.

## Overlay examples

<Tabs
  defaultValue="alert"
  values={[
    { label: 'Alert', value: 'alert', },
    { label: 'Toast', value: 'toast', }
  ]
}>
<TabItem value='alert'>

The example below demonstrates how to create a simple alert dialog using an Overlay. Touch events outside the alert will be blocked and won't pass through to the content behind the alert since we're specifying `interceptTouchOutside: true` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/alert_android.png')} />

```jsx
const React = require('react');
const { Text, Button, View } = require('react-native');
const { Navigation } = require('react-native-navigation');

function Alert({ componentId, title, message }) {
  const dismiss = () => Navigation.dismissOverlay(componentId);

  return (
    <View style={styles.root}>
      <View style={styles.alert}>
        <Text style={styles.title}>{title}</Text>
        <Text style={styles.message}>{message}</Text>
        <Button title="OK" onPress={dismiss} />
      </View>
    </View>
  );
}

const styles = {
  root: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#00000050',
  },
  alert: {
    alignItems: 'center',
    backgroundColor: 'whitesmoke',
    width: 250,
    elevation: 4,
    padding: 16,
  },
  title: {
    fontSize: 18,
  },
  message: {
    marginVertical: 8,
  },
};

Alert.options = (props) => {
  return {
    overlay: {
      interceptTouchOutside: true,
    },
  };
};

module.exports = Alert;
```

</TabItem>
<TabItem value='toast'>

The example below demonstrates how to show a Toast using an Overlay. A user can interact with the content behind the toast since we've declared `interceptTouchOutside: false` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/toast_android.png')} />

```jsx
const React = require('react');
const { View, Text, StyleSheet, TouchableOpacity } = require('react-native');
const Colors = require('../commons/Colors');
const Navigation = require('../services/Navigation');

const Toast = function ({ componentId }) {
  return (
    <View style={styles.root}>
      <View style={styles.toast}>
        <Text style={styles.text}>This a very important message!</Text>
        <TouchableOpacity
          style={styles.button}
          onPress={() => Navigation.dismissOverlay(componentId)}
        >
          <Text style={styles.buttonText}>OK</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  root: {
    flex: 1,
    flexDirection: 'column-reverse',
  },
  toast: {
    elevation: 2,
    flexDirection: 'row',
    height: 40,
    margin: 16,
    borderRadius: 20,
    backgroundColor: Colors.accent,
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  text: {
    color: 'white',
    fontSize: 16,
    marginLeft: 16,
  },
  button: {
    marginRight: 16,
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
});

Toast.options = {
  layout: {
    componentBackgroundColor: 'transparent',
  },
  overlay: {
    interceptTouchOutside: false,
  },
};

module.exports = Toast;
```

</TabItem>
</Tabs>

---

### Website Versioned Docs Version 6.12.2 Docs Docs Passing Data To Components (`website/versioned_docs/version-6.12.2/docs/docs-passing-data-to-components.mdx`)

---
id: passing-data-to-components
title: Passing data to components
sidebar_label: Passing data to components
---

## Initial props

React components use [props](https://facebook.github.io/react-native/docs/props) to receive data when they are created. When displaying the [component](../api/layout-component) layout, you can pass initial props to components using the `passProps` property.

In this example, we push the `UserProfile` screen and pass two initial props to it:

```js
Navigation.push(this.props.componentId, {
  component: {
    name: 'UserProfile',
    id: 'PROFILE_SCREEN_ID'
    passProps: {
      name: 'John Doe',
      status: 'online'
    }
  }
});
```

:::tip Serialization
passProps don't need to be serializable. You can use this mechanism to pass lambda functions or even React Components.
:::

## Handling passProps in static options

Each component can have a static options property which is used to configure the style properties of elements on the screen when that component is displayed. 

Static options can either be a simple object, or a function which accepts `passProps` as an argument. Sometimes when declaring components, not all style properties are known. For example, a user profile screen will usually have the user's name as the TopBar title text. Therefore the title must be configured dynamically when pushing the screen.

Following the code example [above](passing-data-to-components#initial-props), lets see how to use props passed in the push command to set the TopBar title.

```jsx
class UserProfileScreen extends React.Component {
  static options(props) {
    return {
      topBar: {
        title: {
          text: props.name
        }
      }
    };
  }
}
```

## Updating props

To update a component's props, use the [Navigation.updateProps()](../api/component#updateprops) command. Updating props triggers the component lifecycle methods related to [updating](https://reactjs.org/docs/react-component.html#updating).

Notice that we're using the component `id` in order to update props of this specific instance of the component.

```js
Navigation.updateProps('PROFILE_SCREEN_ID', {
  status: 'offline'
});
```

---

### Website Versioned Docs Version 6.12.2 Docs Docs Playground App (`website/versioned_docs/version-6.12.2/docs/docs-playground-app.mdx`)

---
id: playground-app
title: Playground app
sidebar_label: Playground app
---

### Running The Project

If you want to have a quick look around and test things out, you can run the playground app, bundled with this repo.

1. Install dependencies via `npm install` (if you haven't already) and `npm run pod-install` (for iOS)
2. Run the playground project on Android and iOS
    - `npm run start` to get the packager running in the terminal, leave it open
    - **iOS**: open `./playground/ios` in Xcode and run it
    - **Android**: open `./playground/android` in Android Studio and run it
3. You can run tests if / when you need to (list of scripts [available here](meta-contributing#scripts)). Before
you start changing things, make sure everything works.
	- To easily run all tests in parallel `npm run test-all`

---

### Website Versioned Docs Version 6.12.2 Docs Docs Root (`website/versioned_docs/version-6.12.2/docs/docs-root.mdx`)

---
id: root
title: Root
sidebar_label: Root
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

The root is where the application layout structure is defined. It is typically the first UI element a user interacts with. The root can be changed multiple times during the lifespan of the application. For example, if an app requires users to login, it's common to use a stack-based root and transition to either tabs- or SideMenu-based root if login is successful.

## Setting root on app launch
RNN exposes an appLaunched listener which is invoked whenever root needs to be set.

On iOS, the app launched event is usually emitted once in the lifespan of the application - when the app is opened for the first time. On Android things become a little bit more complicated. Like on iOS, the event is emitted when an app is opened for the first time. Since the system can destroy the Activity when the app is in the background to free resources, the event is emitted when the app returns to foreground after the activity has been destroyed.

```js
Navigation.events().registerAppLaunchedListener(() => {
  Navigation.setRoot({
    root: {

    }
  });
});
```

:::important
registerAppLaunchedListener() must be called as soon as the bundle is executed. Otherwise the event, which is emitted from native to JS, won't be handled at the correct moment in time.
::::

## Conditional initial root
A common use case is to set the initial root according to a condition of some sort. For example:

> If a user is logged in, show the application main root; otherwise show a login screen.

To do this, simply set the appropriate root according to your needs.
```js
Navigation.events().registerAppLaunchedListener(() => {
  if (isUserLoggedIn()) {
    setMainRoot();
  } else {
    setLoginRoot();
  }
});
```

## Common root structures

<Tabs
  defaultValue='stack'
  values={[
    { label: 'Stack root', value: 'stack' },
    { label: 'BottomTabs root', value: 'bottomTabs' },
    { label: 'SideMenu root', value: 'sideMenu' }
  ]
}>

<TabItem value='stack'>
Stacks are usually used as root for small scale apps or for short-lived flows within one big app. For example, here's a login flow:

```js
Navigation.setRoot({
  root: {
    stack: {
      children: [
        {
          component: {
            name: 'LOGIN_SCREEN'
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='bottomTabs'>
Typically, stacks are used as direct children of BottomTabs and each child is an independent root. This lets users seamlessly switch between tabs as each tab has its own navigation hierarchy.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      children: [
        {
          stack: {
            children: [
              {
                component: {
                  name: 'FEED_SCREEN'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'CHAT_LIST'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'PROFILE_SCREEN'
                }
              }
            ]
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='sideMenu'>
When a SideMenu layout is used as root, the center screen would typically be a stack. The center stack should be treated as a root - you can push child screens into it, or replace it alltogether by calling `setStackRoot`.

```js
Navigation.setRoot({
  root: {
    sideMenu: {
      center: {
        stack: {
          children: [
            {
              component: {
                name: 'HOME_SCREEN'
              }
            }
          ]
        }
      },
      left: {
        component: {
          name: 'MENU_SCREEN'
        }
      }
    }
  }
});
```

</TabItem>
</Tabs>

---

### Website Versioned Docs Version 6.12.2 Docs Docs Screen Lifecycle (`website/versioned_docs/version-6.12.2/docs/docs-screen-lifecycle.mdx`)

---
id: screen-lifecycle
title: Screen Lifecycle
sidebar_label: Screen Lifecycle
---

Any React Component registered with react-native-navigation is enhanced with two additional lifecycle events:

* `componentDidAppear` - called each time a component is revealed to the user
* `componentDidDisappear` - called each time a component is hidden from user's view **as a result of being detached from hierarchy**

These methods compliment React's lifecycle methods:

* `componentDidMount` - called once, when a component is attached to hierarchy **for the first time**
* `componentWillUnmount` - called once, when a component is destroyed

### Mounting
These methods are called in the following order when a component is created and attached to hierarchy.

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

### Unmounting
These methods are called when a component is being removed from hierarchy

* componentDidDisappear()
* componentWillUnmount()

### Modal

When a modal is displayed, depending on the [modalPresentationStyle](/react-native-navigation/api/options-root#modalpresentationstyle), content behind it might be detached from hierarchy. This affects the visibility events which are emitted to the content behind the modal.

When Modals with `pageSheet` or `overCurrentContext` modalPresentationStyle are displayed, previous content is still visible to the user. Thus `componentDidDisappear` event is **not** emitted.

Same is applied when a modal is dismissed. If it was originally presented with `pageSheet` or `overCurrentContext` modalPresentationStyle, when that modal is then dismissed, the previous context won't receive a `componentDidAppear` event.

### Overlay
These methods are called in the following order when a component is displayed as an Overlay:

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

:::note
Content displayed behind an Overlay does not receive the `componentDidDisappear`, since it's still visible to user and attached to the hierarchy.
:::

---

### Website Versioned Docs Version 6.12.2 Docs Docs Showcases (`website/versioned_docs/version-6.12.2/docs/docs-showcases.mdx`)

---
id: showcases
title: Showcases
sidebar_label: Showcases
---

## Apps
### Hekla for Hacker News

A hacker news client built from the ground up with v2 of react-native-navigation. 

It is a tab-based app and utilizes Split Layout for iOS tablets, 3D touch and more.

- [Source code](https://github.com/birkir/hekla)
- [Download iOS](https://itunes.apple.com/us/app/hekla/id1405096983?mt=8)
- [Download Android](https://play.google.com/store/apps/details?id=is.pipe.hekla)

## Starter Kits
* [kanzitelli/expo-rnn-starter](https://github.com/kanzitelli/expo-rnn-starter) - Simple yet practical starter with React Native Navigation and [Expo Modules](https://docs.expo.io/bare/installing-unimodules/), [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) and [Redux](https://github.com/reduxjs/redux) (pick one) and more goodies inside such as Typescript, [RNN Hooks](https://github.com/underscopeio/react-native-navigation-hooks), [RN Vector Icons](https://github.com/oblador/react-native-vector-icons), [RN Gesture Handler](https://github.com/kmagiera/react-native-gesture-handler). As an example, basic Reddit App implemented in two ways: using [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) in `/srcMobX` and using [Redux](https://github.com/reduxjs/redux) in `/srcRedux`.
* [atoami/react-native-navigation-redux-starter-kit](https://github.com/atoami/react-native-navigation-redux-starter-kit) - React Native Navigation(v2) Starter Kit with Redux, Saga, ESLint, Babel and Jest 😎
* [alexwasner/react-native-mobx-firebase-starter](https://github.com/alexwasner/react-native-mobx-firebase-starter) - A React Native starter app with React Native Navigation(v2), MobX, Firebase, Lottie and More 🤓

* [hsyndeniz/react-native-quick-start](https://github.com/hsyndeniz/react-native-quick-start) - A React Native starter app with React Native Navigation, Redux, Firebase, Social Auth, Phone Auth, Push Notifications, Google Maps, Google Admob, Lottie and More 🤓

### Playground

The playground example is a place where we showcase and test all features of react-native-navigation.

```bash
git clone https://github.com/wix/react-native-navigation
cd react-native-navigation
npm install

# for iOS:
npm run xcode # Opens XCode
npm start # Starts the packager on linux like systems

# for Android:
# 1. open Android Studio inside ".\playground"
# 2. start a emulator
npm run start-windows # Start the packager if you are on a windows system

# Run the app in Simulator or on Device from within XCode/Android Studio
```

---

### Website Versioned Docs Version 6.12.2 Docs Docs SideMenu (`website/versioned_docs/version-6.12.2/docs/docs-sideMenu.mdx`)

---
id: sideMenu
title: Side Menu
sidebar_label: Side Menu
---

SideMenu provides access to destinations in the app from an easy to access menu which is accessible to the user via horizontal swipe gesture or a menu button.

## Opening programmatically

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu. The menu is opened by setting its visible option to visible.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Opening via the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button at the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

## Pushing to the center layout from a menu
A common use case when using SideMenus is to interact with the center layout, e.g. pushing a screen to a stack in the center layout when a user clicks on a button from one of the menus.

In order to interact with the stack, we'll first assign it a predefined id. For example:

```js
sideMenu: {
  center: {
    stack: {
      id: 'CenterStack',
      children: []
    }
  },
  left: {
    ...
  }
}
```

Now that we've defined an `id` for out stack, we can go ahead and push our screen to it. If we're pushing while the SideMenu is open, we'll need to make sure we close it by updating the visibility option of the relevant menu (left or right).

```js
Navigation.push('CenterStack', {
  component: {
    name: Screens.Pushed,
    options: {
      sideMenu: {
        left: {
          visible: false
        }
      }
    }
  }
});
```

---

### Website Versioned Docs Version 6.12.2 Docs Docs Stack (`website/versioned_docs/version-6.12.2/docs/docs-stack.mdx`)

---
id: stack
title: Stack
sidebar_label: Stack
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

A stack is a container layout promoting a hierarchical navigation. It is used for navigating between screens at consecutive levels of hierarchy, steps in a flow or across an app.

The first child in the stack (represented by the `children` array) is the root and is displayed at the bottom of the stack. The last child in the children array is the child currently being displayed.

In this layout, only a single child screen is visible at any given time and consecutive screen can be added to the top of the stack using the `Navigation.push` command. Tapping the back button will pop the stack and remove the top most screen.

The stack manages the TopBar at the top of the stack. The TopBar displays the current screens' title and buttons. It can be hidden with the `topBar: { visible: false }` option. By default, screens are rendered below the TopBar. This behavior can be changed by setting `topBar: { drawBehind: true }` in the current screens' options.

# Layout Examples

<Tabs
  defaultValue="single"
  values={[
    { label: 'Single child', value: 'single', },
    { label: 'Multiple Children', value: 'multiple', }
  ]
}>
<TabItem value="single">


A stack declared with a single child.

```js
const stack = {
  children: [
    {
      component: {
        name: 'MyComponent',
      },
    },
  ],
};
```

</TabItem>
<TabItem value="multiple">


A stack can be initialized with more than one child, in which case the last child will be the currently displayed child and the first child will be hidden. In this case the back button will be visible automatically, clicking it will go back in the stack revealing the first (previous) child.
Once the root child becomes visible, the back button is hidden.

```js
const stack = {
  children: [
    {
      component: {
        name: 'RootComponent',
      },
    },
    {
      component: {
        name: 'SecondComponent',
      },
    },
  ],
};
```

</TabItem>
</Tabs>


## TopBar Buttons

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

:::tip Always assign titles to buttons!
When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.
:::

### Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](../api/options-button#showasaction) options to control when the button should appear in the menu.

### Left button

Left buttons behave like right buttons with two caveats on Android:

- Only a single left button is allowed
- Textual left button isn't supported

### Using a react component in a button

:::caution
At the moment, custom buttons in `leftButtons` are supported only on iOS.
:::

Sometimes we require more from our buttons. In order to support every product need React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as their custom view:

```js
topBar: {
  rightButtons: [
    {
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

### Updating props of custom buttons

To update props of a mounted component used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger Reacts component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0
        },
      },,
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

### Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

#### Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

#### Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

## Back Button

The back button is added automatically when two or more screens are pushed into the stack.

### Styling the back button

The back button's style can be customized by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

### Controlling visibility

The back buttons visibility can be controlled with the visible property.

```js
backButton: {
  visible: false;
}
```

### Changing visibility programmatically

Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false,
  },
});
```

### Handling the back button

Handling the back button is not possible. However, you can set a left button with a chevron and handle it like you'd handle any other button and calling `Navigation.pop` when desired.

## Interacting programmatically

The Navigation object provides ways to programmatically manipulate the stack.

### Interact with the Stack by componentId

Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN',
      },
    });
  };
}
```

### Interact with the Stack by a predefined id

Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent',
          },
        },
      ],
    },
  },
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen',
    },
  });
}
```

## Disabling back navigation

## Handling back navigation

---

### Website Versioned Docs Version 6.12.2 Docs Meta Contributing (`website/versioned_docs/version-6.12.2/docs/meta-contributing.mdx`)

---
id: meta-contributing
title: Contributing
sidebar_label: Contributing
---

Thank you for showing interest in contributing to React-Native-Navigation! This project is developed and maintained by Wix in collaboration with the community.

There are various ways in which you can contribute to this library, not all require knowledge or expertise in native development. Listed below is all you need to get started with your first contribution.

## Stack Overflow

Stack Overflow is used by developers to find answers and troubleshoot code. Users are encouraged to post questions on SO and tag them with the [wix-react-native-navigation](https://stackoverflow.com/questions/tagged/wix-react-native-navigation) tag. Answering issues on SO is very helpful and beneficial to the community, only this time, there's a personal angle - you can boost your SO ranking and rack up points quickly.

## Discord

Another popular communication channel is our [Discord channel](https://discord.gg/DhkZjq2) where users post questions and consult with each other. You're welcome to join the discussions and answer questions. This is also a great place to meet other community members and project maintainers.

## GitHub Issues

### Open an issue
Found a bug? Missing a feature? Go ahead and open an issue! Make sure to add all details mentioned in the issue template. If you're interested in suggesting a big change, please speak to one of the admins on [Discord](#discord) to coordinate your effort.

### Respond to issues
Although the issue tracker is used solely for bug reports, issues are frequently opened for questions or to request assistance. As the project grows in popularity, more issues remain unanswered for long periods of time.

Some issues can be trivial and easy to pinpoint - a missing import statement or apostrophe, wrong layout structure, etc. If you're an experienced user, helping out newcomers can be quite satisfying and allows maintainers to focus on features and bug fixes.

Some issues are tagged as ["looking for contributors"](https://github.com/wix/react-native-navigation/labels/user%3A%20looking%20for%20contributors). These issues have been recognized by the team, but aren't prioritized by Wix developers due to lack of time or for some other reason. We leave these issues to our community and you're more than welcome to take a crack at them. If you'd like to submit a PR, see [these instructions](#running-the-project) on how to run the project locally.

### Provide reproductions
Reproducing bugs takes time. Lots of time. Usually that's because an issue is lacking important information, which then causes lots of back and forth communication between maintainers and users. Help us address more bugs and issues by providing reproductions.

Providing reproductions improves the chances of an issue being prioritized by maintainers!

If an issue is reproduced with a specific combination of options, posting these options will usually suffice. If a specific layout structure is involved or specific actions need to be performed in a certain order - then we ask that you fork the project and push a branch with a reproduction to the Playground app.

Check out the [list of issues requiring reproductions](https://github.com/wix/react-native-navigation/labels/user%3A%20requires%20reproduction).

## Submitting PRs
So you've fixed a bug or added a feature and you're ready to submit a pull request 🎉🎊 Make sure the title is clear and describes the reason for the PR. Please include any information you can which will help us understand the reasons for the PR, what it fixes and what it changes. Please include before/after pictures/gifs when appropriate.

## Workflow
This project is driven by tests. Before implementing any feature or fixing any bug, a failing test (e2e or unit or both) should be added, depending on the environment of where the fix should be implemented. For example, for an API change, a failing e2e should be written. For a small bug fix in Android, for example, a unit test in Android should be added.

This will ensure good quality throughout the life of the project and will help avoid unexpected breakages.

No PR will be accepted without adequate test coverage.

If you need help running the project, have a look at the [Playground app](playground-app) section. You can run the tests using the scripts below. 


### Tests and the Playground app
Besides an overview of basic React Native Navigation functionality, the [Playground app](playground-app) can (and rather should) be used for e2e tests and reproductions. If your change requires an e2e, add it to the playground app, to the appropriate screen. Again, quick setup instructions available in [Playground app](playground-app) section of these docs.

:::tip
If a screen contains too many buttons, e2e tests might fail if the button is positioned out of screen bounds because Detox matchers detect it's invisible.
:::

### Enable linter
The project uses [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) to ensure code style consistency across the codebase. Make sure to install these plugins in your IDE.

A pre-commit hook will verify that the linter passes when committing.

### Playground app Folder Structure

| Folder | Description |
| ------ | ----------- |
| `lib` | The project itself composed of: |
| `lib/android` | android sources and unit tests |
| `lib/ios` | iOS sources and unit tests |
| `lib/src` | TypeScript sources and unit tests |
| `lib/dist` | compiled javascript sources and unit tests |
| `lib/dist/index.js` | the entry point for `import Navigation from 'react-native-navigation'` |
| `e2e` | [detox](https://github.com/wix/detox) e2e tests on both Android and iOS |
| `playground` | The end-user project all e2e tests run against. Contains its own `src`, `android` and `ios`. Does not have its own package.json, depends on the local `<root>/lib` for faster local development (no need to `npm install` locally). |
| `integration` | misc javascript integration tests, proving integration with other libraries like redux |
| `scripts` | all scripts |

### Scripts

| Command | Description |
| ------- | ----------- |
| `npm install` | installs dependencies |
| `npm run build` | compiles TypeScript sources `./lib/src` into javascript `./lib/dist` |
| `npm run clean` | cleans all build directories, stops packager, fixes flakiness by removing watchman cache, etc. |
| `npm run start` | starts the react-native packager for local debugging |
| `npm run xcode` | for convenience, opens xcode in this project |
| `npm run install-android`  |  builds playground debug/release version and installs on running android devices/emulators. <br></br> **Options:** `-- --release` |
| `npm run uninstall-android` | uninstalls playground from running android devices/simulators |
| `npm run test-js` | runs javascript tests and coverage report |
| `npm run test-unit-ios` | runs ios unit tests in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-unit-android` | runs android unit tests in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-e2e-ios` | runs the ios e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release`|
| `npm run test-e2e-android` | runs the android e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-all` | runs all tests in parallel |

---

### Website Versioned Docs Version 6.12.2 Docs SideMenu Disable (`website/versioned_docs/version-6.12.2/docs/sideMenu-disable.mdx`)

---
id: sideMenu-disable
title: Disable Open and Close gesture
sidebar_label: Open and Close Gesture
---

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Open by pressing on the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button in the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

---

### Website Versioned Docs Version 6.12.2 Docs Stack BackButton (`website/versioned_docs/version-6.12.2/docs/stack-backButton.mdx`)

---
id: stack-backButton
title: The Back button
sidebar_label: Back button
---

The back button is added automatically when two or more screens are pushed into the stack.

## Styling the back button
The back button's style can be customised by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

## Controling visibility
The back buttons visbility can be controlled with the visible property.

```js
backButton: {
  visible: false
}
```

## Changing visbility programmatically
Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false
  }
});
```

## Handling the back button
Handling the back button is not possible. However, you can set a left button with a chevron and handle it like you'd handle any other button and calling `Navigation.pop` when desired.

---

### Website Versioned Docs Version 6.12.2 Docs Stack BackNavigation (`website/versioned_docs/version-6.12.2/docs/stack-backNavigation.mdx`)

---
id: stack-backNavigation
title: Back Navigation
sidebar_label: Back navigation
---

## Disabling back navigation

## Handling back navigation

---

### Website Versioned Docs Version 6.12.2 Docs Stack Buttons (`website/versioned_docs/version-6.12.2/docs/stack-buttons.mdx`)

---
id: stack-buttons
title: TopBar Buttons
sidebar_label: TopBar Buttons
---

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

> When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.

# Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](#showasaction) options to control when the button should appear in the menu.

# Left button

Left buttons behave like right buttons with two caveats on Android:

- Only a single left button is alowed
- Textual left button isn't supported

# Using a react component in a button

> ⚠️At the moment, Android only supports using custom buttons in `rightButtons`.

Sometimes we require more from our buttons. In order to support every product need React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as thier custom view:

```js
topBar: {
  rightButtons: [
    {
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

## Updating props of custom buttons

To update props of a mounted compoennt used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger React's component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0
        },
      },,
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

# Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

## Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

## Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

---

### Website Versioned Docs Version 6.12.2 Docs Stack Programmatically (`website/versioned_docs/version-6.12.2/docs/stack-programmatically.mdx`)

---
id: stack-programmatically
title: Interact programmatically with the Stack
sidebar_label: Interact programmatically
---

The Navigation object provides ways to programmatically manipulate the stack.

## Interact with the Stack by componentId
Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN'
      }
    });
  }
}
```

## Interact with the Stack by a predefined id
Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent'
          }
        }
      ]
    }
  }
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen'
    }
  });
}
```

---

### Website Versioned Docs Version 6.12.2 Docs Style Animations (`website/versioned_docs/version-6.12.2/docs/style-animations.mdx`)

---
id: style-animations
title: Animations
sidebar_label: Animations
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Various UI elements can be animated by declaring animation options.
You can change the default animations for various commands, like push and pop, and even animate elements in
your screens during screen transitions.

#### Animation properties

The following properties can be animated with our animation framework:

- **x** - Translate the view to a coordinate along the x axis.
- **y** - Translate the view to a coordinate along the y axis.
- **translationX** - Translate the view along the x axis relative to its current x position.
- **translationY** - Translate the view along the y axis relative to its current y position.
- **alpha** - Apply alpha animation to the view. A value of 0 means the view is not visible, 1 means it's visible.
- **scaleX** - Scale the view on the x axis. A value of 1 means that no scaling is applied.
- **scaleY** - Scale the view on the y axis. A value of 1 means that no scaling is applied.
- **rotationX** - Applies rotation around the x axis (in degrees, passed as a float).
- **rotationY** - Applies rotation around the y axis (in degrees, passed as a float).
- **rotation** - Rotates the view on all axis. Positive values result in clockwise rotation.

## Layout animations

### Stack animations

When animating screens in and out of a stack, there are three elements you can work with:

1. **content** - screen being pushed or popped
2. **topBar** - stack's TopBar
3. **bottomTabs** - if stack is a child of a bottomTabs layout, we can control the `hide` and `show` animations of the bottomTabs.

The following example demonstrates how to replace the default push and pop animations with slide animations.

<Tabs
  defaultValue="push"
  values={[
    { label: 'Push', value: 'push', },
    { label: 'Pop', value: 'pop', },
  ]
}>
<TabItem value="push">

```js
options: {
  animations: {
    push: {
      content: {
        translationX: {
          from: require('react-native').Dimensions.get('window').width,
          to: 0,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
<TabItem value="pop">

```js
options: {
  animations: {
    pop: {
      content: {
        translationX: {
          from: 0,
          to: -require('react-native').Dimensions.get('window').width,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
</Tabs>

### Modal animations

Modal animations are declared similarly to stack animations, only this time we animate the entire view and not only part of the UI (content).

<Tabs
  defaultValue="show"
  values={[
    { label: 'Show', value: 'show', },
    { label: 'Dismiss', value: 'dismiss', },
  ]
}>
<TabItem value="show">

The following example demonstrates how to show a modal with a fade-in animation.

```js
options: {
  animations: {
    showModal: {
      alpha: {
        from: 0,
        to: 1,
        duration: 300
      }
    }
  }
}
```

</TabItem>
<TabItem value="dismiss">

The following example demonstrates how to dismiss a modal with a fade-out animation.

```js
options: {
  animations: {
    dismissModal: {
      alpha: {
        from: 1,
        to: 0,
        duration: 300
      }
    }
  }
}
```

</TabItem>
</Tabs>

## Shared element transitions

Shared element transitions allow us to provide visual continuity when navigating between destinations. This also focuses user attention on a particular significant element, which then also gives such user better context when transitioning to some other destination.

:::caution
At the moment, the transition is available for push and pop commands. We are working on expanding supported commands to show/dismiss modal and change BottomTabs.
:::

### Transition breakdown

Let's take a more in-depth look at the following example, which you can find in the playground app:

> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.js) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.js)

<p align="center">
  <img alt="Shared Element Transition" src={useBaseUrl('img/sharedElement.gif')} />
</p>

Four elements are animated in this example. Let's list the elements involved in the transition and note which properties are being animated.

- **image** - the item image is animated to the next screen.

  - image scale (resizeMode)
  - position on screen

- **image background** - each item has a "shadow" view which transitions to the next screen and turns into a colorful header.

  - scale
  - position on screen
  - color

- **title** - the title of the item is animated to the next screen.

  - font size
  - font color
  - position on screen

- **Description** - the description of the item in the destination screen.
  - fade-in
  - translation y

### Implementing shared element transitions

#### Step 1 - set a nativeID prop to elements in the source screen

In order for RNN to be able to detect the corresponding native views of the elements,
each element must include a unique `nativeID` prop.

```jsx
<Image
  source={item.image}
  nativeID={`image${item.id}`}
  style={styles.image}
  resizeMode={'contain'}
/>
```

#### Step 2 - set a nativeID prop to elements in the destination screen

```jsx
<Image source={this.props.image} nativeID={`image${this.props.id}Dest`} style={styles.image} />
```

#### Step 3 - Declare the shared element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          sharedElementTransitions: [
            {
              fromId: `image${item.id}`,
              toId: `image${item.id}Dest`,
            },
          ],
        },
      },
    },
  },
});
```

## Element Transitions

Element transitions also allow you to animate elements during shared element transitions.

### Recreating

#### Step 1 - Set a nativeID prop to the element you'd like to animate

An element can either be in the source or destination screen.

```jsx
<Text nativeID="description" style={styles.description}>
  {this.props.description}
</Text>
```

#### Step 2 - Declare the element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          elementTransitions: [
            {
              id: 'description',
              alpha: {
                from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1
                duration: SHORT_DURATION,
              },
              translationY: {
                from: 16, // Animate translationY from 16dp to 0dp
                duration: SHORT_DURATION,
              },
            },
          ],
        },
      },
    },
  },
});
```

## Peek and Pop (iOS 11.4+)

react-native-navigation supports [Peek and pop](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/#//apple_ref/doc/uid/TP40016543-CH1-SW3) feature in iOS 11.4 and newer.

This works by passing a ref to a component you want to transform into peek view. We have included a handy component to handle all the touches and ref for you:

```jsx
const handlePress ({ reactTag }) => {
  Navigation.push(this.props.componentId, {
    component {
      name: 'previewed.screen',
      options: {
        preview: {
          reactTag,
          height: 300,
          width: 300,
          commit: true,
          actions: [{
            title: "Displayed Name",
            id: "actionId",
            style: 'default', /* or 'selected', 'destructive'*/
            actions: [/*define a submenu of actions with the same options*/]
          }]
        },
      },
    },
  });
};

const Button = (
  <Navigation.TouchablePreview
    touchableComponent={TouchableHighlight}
    onPress={handlePress}
    onPressIn={handlePress}
  >
    <Text>My button</Text>
  </Navigation.TouchablePreview>
);
```

All options except for reactTag are optional. Actions trigger the same event as [navigation button presses](https://wix.github.io/react-native-navigation/#/docs/topBar-buttons?id=handling-button-press-events). To react when a preview is committed, listen to the [previewCompleted](https://wix.github.io/react-native-navigation/#/docs/events?id=previewcompleted-ios-114-only) event.

---

### Website Versioned Docs Version 6.12.2 Docs Style Constants (`website/versioned_docs/version-6.12.2/docs/style-constants.mdx`)

---
id: style-constants
title: Constants
sidebar_label: Constants
---

React Native Navigation exposes a set of constants which can be used to get the dimensions of various navigation elements on the screen: StatusBar, TopBar and BottomTabs.

## When are constants evaluated
Some of the values exposed through the constants API are actually evaluated only after the UI is created (`setRoot` has been called) and therefore are not accessible through static getters.

For example, if you need to get the height of the BottomTabs, you'll first need to have BottomTabs visible on the screen and only then retrieve their height via the constants API.

:::important
We recommend you don't cache the actual constants object returned by `await Navigation.constants()` as it might not be accurate later on when, for example, a new root is set or orientation changes.
:::

## API
As explained above, constants are evaluated in native each time the API is invoked. That's why `Navigation.constants()` returns a promise and the use is as follows:

```js
const { Navigation } = require('react-native-navigation');
const {
  statusBarHeight,
  topBarHeight,
  bottomTabsHeight
} = await Navigation.constants();
```

---

### Website Versioned Docs Version 6.12.2 Docs Style Fonts (`website/versioned_docs/version-6.12.2/docs/style-fonts.mdx`)

---
id: style-fonts
title: Changing fonts
sidebar_label: Changing fonts
---

Before you begin using your own fonts, you'll first need to add them to the app project.

* **Android** - add the `.ttf` or `.otf` files to `src/main/assets/fonts/`
* **iOS** - follow this [guide](https://medium.com/react-native-training/react-native-custom-fonts-ccc9aacf9e5e)

Once we've added the font files to our project, we can star using them in options.

:::note
When declaring fonts in options, use only the file name without the file type suffix.
:::

## BottomTab font

```js
options: {
  bottomTab: {
    fontFamily: 'helvetica'
  }
}
```

## Button font

```js
options: {
  rightButtons: [
    {
      id: 'SAVE_BUTTON',
      text: 'Save',
      fontFamily: 'helvetica'
    }
  ],
  leftButtons: [
    {
      id: 'CANCEL_BUTTON',
      text: 'Cancel',
      fontFamily: 'helvetica'
    }
  ]
}
```

## Title font

```js
options: {
  topBar: {
    title: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Subtitle font

```js
options: {
  topBar: {
    subtitle: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Back button

In iOS the back button will display the title of the previous screen. Use the `backButton` option to modify its font family.

```js
options: {
  topBar: {
    backButton: {
      fontFamily: 'helvetica'
    }
  }
}
```

---

### Website Versioned Docs Version 6.12.2 Docs Style Orientation (`website/versioned_docs/version-6.12.2/docs/style-orientation.mdx`)

---
id: style-orientation
title: Orientation
sidebar_label: Orientation
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Locking orientation
Orientation can be locked either in the layout level, or across the app via default options. You can declare orientations you'd like your app to support in default options.

<Tabs
  defaultValue="defaultOptions"
  values={[
    { label: 'Locking orientation in default options', value: 'defaultOptions', },
    { label: 'Locking root layout orientation', value: 'root', },
    { label: 'Showing landscape modal', value: 'modal', }
  ]
}>
<TabItem value="defaultOptions">

Setting orientation in default options will affect all screens in all hierarchy levels. It's still possible to override orientation for specific screens.

```js
Navigation.setDefaultOptions({
  layout: {
    orientation: ['portrait']
  }
});
```

</TabItem>
<TabItem value="modal">

The following example demonstrates how to show a modal in landscape orientation.

```js
Navigation.showModal({
  component: {
    name: 'VideoPlayer'
    options: {
      layout: {
        orientation: ['landscape']
      }
    }
  }
});
```

</TabItem>
<TabItem value="root">

Applying orientation in the root level will affect all screens in the root hierarchy level. It **will not** apply to modals.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      options: {
        layout: {
          orientation: ['portrait']
        }
      },
      children: [
        ...
      ]
    }
  }
});
```

</TabItem>
</Tabs>

## Changing orientation dynamically

Changing orientation dynamically through `Navigation.mergeOption()` is supported only on Android.

```js
Navigation.mergeOptions(this.props.componentId, {
  layout: {
    orientation: ['landscape']
  }
});
```

---

### Website Versioned Docs Version 6.12.2 Docs Style Screens (`website/versioned_docs/version-6.12.2/docs/style-screens.mdx`)

---
id: style-options
title: Styling with options
sidebar_label: Options
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

A Screen's look and feel is configured with an [Options](../api/options-root) object. Options can be applied to screens in three ways. Each method of applying options has benefits and draw backs which are important be aware of so we can use the right tool for the job.

## Command options

Options can be passed to layouts as part of a command. For example when pushing a screen. Options passed in commands are typically dynamic options which are determined at runtime.

In the example below we're pushing a user profile screen and we'd like show the user name in the title. To do so, we set the title in the component's options.

```tsx file=./style-screens/command-options.tsx
```

Notice how the title is actually inferred from the `user` object which is set in `passProps`. While this works perfectly fine, declaring the title each time a screen is pushed is a bit tedious and error prone. Later on we'll see a more convenient method to declare dynamic options which are inferred from props.

## Static options

Static options are options that are declared statically **on** the component class. Whenever a screen has a known predefined style, static options should be used as they are evaluated immediately when the screen is created.

<Tabs
  defaultValue="class"
  values={[
    { label: 'Class Component', value: 'class', },
    { label: 'Functional Component', value: 'functional', }
  ]
}>
<TabItem value="class">

```tsx file=./style-screens/static-options-class.tsx
```

</TabItem>
<TabItem value="functional">

```tsx file=./style-screens/static-options-fn.tsx
```

</TabItem>
</Tabs>

### Handle props in static options

Sometimes a screen's style includes properties defined in the calling scope where the screen is used. Like in the user profile screen we've seen above where the the user name is used as the TopBar title. As the user name is unique for each profile, it can't be defined explicitly in the static options.

Luckily, we can access props from static options and set the title from static options! Let's see how this is done:

<Tabs
  defaultValue="class"
  values={[
    { label: 'Class Component', value: 'class', },
    { label: 'Functional Component', value: 'functional', }
  ]
}>
<TabItem value="class">

```tsx file=./style-screens/static-options-props-class.tsx
```

</TabItem>
<TabItem value="functional">

```tsx file=./style-screens/static-options-props-fn.tsx
```

</TabItem>
</Tabs>

Following this approach we can determine options that are dependent on other external factors, such as experiments or A/B tests.

```tsx file=./style-screens/static-options-experiments.tsx
```

## Merge options

The `mergeOptions` command is used to update a layout's style. Keep in mind that the merge happens in native, and not ins JS. This meaning that if `mergeOptions` is called to update a screen's options, the static options declared on the React Component are not affected by mergeOptions.

The following example shows how to update a TopBar background color to red.

```tsx file=./style-screens/merge-options.tsx
```

---

:::warning
**Avoid using mergeOptions in a screen's constructor or in componentDidMount!**
:::

When a screen first appears, it's `constructor` and `componentDidMount` functions are called followed by a `componentDidAppear` event. (read more about screen lifecycle [here](docs-screen-lifecycle.mdx)).

Developers might be tempted to call `mergeOptions` in constructor or componentDidMount to update options. Calling `mergeOptions` before the `componentDidAppear` event has been received has two very negative effects:

1. Updating certain options can trigger additional layout and draw cycles which can have serious impact on performance.
2. Options applied dynamically with the `mergeOptions` command might be handled in native **after** the screen has already appeared. This will result in noticeable flickering and artifacts as options are updated after the initial options have been applied and are visible to the user.

---

### Website Versioned Docs Version 6.12.2 Docs Style Statusbar (`website/versioned_docs/version-6.12.2/docs/style-statusbar.mdx`)

---
id: style-statusBar
title: StatusBar
sidebar_label: StatusBar
---

The StatusBar appearance is controlled through options.

For example, the following options will change the StatusBar background color to white will use dark colors for the StatusBar content (time, battery information, notification icons etc)

```js
options: {
  statusBar: {
    backgroundColor: 'white',
    style: 'dark'
  }
}
```

:::warning Compatibility with StatusBar component
React native's [StatusBar](https://reactnative.dev/docs/statusbar#__docusaurus) component is incompatible with React Native Navigation and you should avoid using it.
:::

## Changing StatusBar style dynamically

As the StatusBar is controlled through options, it can be configured dynamically by calling `Navigation.mergeOptions` with the desired StatusBar options.

For example, here's how you would hide the StatusBar dynamically

```js
Navigation.mergeOptions(this.props.componentId, {
  statusBar: {
    visible: false
  }
});
```

## How keep current StatusBar color when displaying screens

When screens are displayed, the StatusBar color always changes to the color associated with the current screen. If a color isn't specified for a given screen (and thus for the StatusBar), the default (System default or from defaultOptions) color is used. Sometimes you might want to keep the current StatusBar color, for example when displaying an alert or a toast. To keep StatusBar color unchanged when displaying a screen, use `null` as a StatusBar color.

```js
options: {
  statusBar: {
    backgroundColor: null
  }
}
```

---

### Website Versioned Docs Version 6.12.2 Docs Style Theme (`website/versioned_docs/version-6.12.2/docs/style-theme.mdx`)

---
id: style-theme
title: Themes
sidebar_label: Themes
---

A theme is a type of style which is applied to the entire app. It allows you to declare
a consistent style to all Navigation components such as the TopBar and BottomTabs and also
to system elements like the StatusBar and NavigationBar.

## Applying a theme

Themes are applied using `Navigation.setDefaultOptions()` which must be called **before** `Navigation.setRoot()` is called.

```js
// Set the default topBar background color to red
Navigation.setDefaultOptions({
  topBar: {
    background: {
      color: 'red'
    }
  }
});

// That stack's topBar background color will be red, as is set in default options
Navigation.setRoot({
  root: {
    stack: {
      children: [
        ...
      ]
    }
  }
});
```

## Conditional themes with Options Processor

Some style requirements can't be facilitated with the `defaultOptions` api. For example, an app may have a unique theme for screens displayed in a modal or require that modals have a default dismiss button in the TopBar. An Options Processor allow us to mutate the options object of each screen and layout right before they are displayed.

Lets see how we can leverage this API to add a dismiss button to the TopBar when showing a modal.

```tsx file=./style-theme/option-processor.tsx
```

The Options Processors can also be used to set default options for buttons, here's how:

```tsx file=./style-theme/option-processor-defaults.tsx
```

## Conditional themes with Layout Processor

Layout Processor is similar in concept to the Options Processor discussed above. While Options Processor is invoked for each options object, Layout Processor is invoked once on the entire (layout)['../api/layout-layout/'] tree passed to the Navigation command.

Through the Layout Processor we can access the layout and it's children, and mutate both options and passProps before the layout is displayed. In this example we iterate on the stack's children and set a dark TopBar color according to a `theme` property in the child's props.

```tsx file=./style-theme/layout-processor.tsx
```

## Changing theme dynamically

Apps can have multiple themes and sometimes you might need to change theme dynamically. To change current theme, simply call `Navigation.setDefaultOptions()` with updated theme options, following that with a call to `Navigation.setRoot()`. The reason we need to setRoot once more is because `Navigation.setDefaultOptions()` does not apply options to screens which had already been created.

---

### Website Versioned Docs Version 6.12.2 Docs Third Party Mobx (`website/versioned_docs/version-6.12.2/docs/third-party-mobx.mdx`)

---
id: third-party-mobx
title: MobX
sidebar_label: MobX
---
import useBaseUrl from '@docusaurus/useBaseUrl';

MobX is one of the most popular state management libraries used by applications sized from small to large. 
With the introduction of the new React Context API, MobX can now be very easily integrated in React Native Navigation
projects.

:::info Note
With the introduction of the new Context API, there is no need to use `Provider` pattern with MobX and you
can now just use the React Context API.

Also the example uses `mobx-react-lite` but you can use the normal `mobx-react`.
:::

## Sharing a store between multiple screens

In the example below we will be creating a small Counter app. We will learn how to integrate Mobx with React-Native-Navigation and demonstrate how updating the store from one component, triggers renders in other components connected to the same store.

Once you finish implementing the example, your screen should look similar to this:
<img width="30%" src={useBaseUrl('/img/mobx_counter.png')} />

### Step 1 - Create a Counter store
Let's first create a counter store using MobX. Our store has a single `count` object and two methods to increment and decrement it.

```tsx file=./third-party-mobx/counter-store.tsx
```

### Step 2 - Consuming the store
You can consume the Counter store in any React components using `React.useContext`.

```tsx file=./third-party-mobx/counter-screen.tsx
```

## How to use MobX persistent data
Often the app will require a persistent data solution and with MobX you can use [`mobx-react-persist`](https://github.com/pinqy520/mobx-persist).
It only takes few extra steps to integrate the library.

```tsx file=./third-party-mobx/persistent-data.tsx
```

---

### Website Versioned Docs Version 6.12.2 Docs Third Party React Context (`website/versioned_docs/version-6.12.2/docs/third-party-react-context.mdx`)

---
id: third-party-react-context
title: React Context API
sidebar_label: React Context API
---

## React Context API 
React Context API provides a easy way to pass data through the component tree without having to pass props down 
manually at every level. You can find more about the Context API in [React documentation](https://reactjs.org/docs/context.html).

You can use the React Context API with React Native Navigation with a limitation. In this example, we are going to create a screen which uses the Counter Context.

:::important Limitation
As RNN screens are not part of the same component tree, updating the values in the shared context does not trigger a re-render across all screens.
However you can still use the React.Context per RNN screen component tree.

If you need to trigger a re-render across all screens, there are many popular third party libraries such as 
[MobX](third-party-mobx.mdx) or Redux.
:::

## Create a Counter context

```tsx file=./third-party-react-context/CounterContext.tsx
```

## Register the screen
When registering the screen that will be using the Counter Context, we need to wrap it
with the Counter Context Provider we created earlier.

```tsx file=./third-party-react-context/index.tsx
```

## Consuming the context
You can consume the Counter Context any way you want such as `Provider.Consumer` or `React.useContext` like in the 
example below.

```tsx file=./third-party-react-context/App.tsx
```

```tsx file=./third-party-react-context/App-consumer.tsx
```

---

### Website Versioned Docs Version 6.12.2 Docs Third Party Typescript (`website/versioned_docs/version-6.12.2/docs/third-party-typescript.mdx`)

---
id: third-party-typescript
title: TypeScript
sidebar_label: TypeScript
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Strongly typed components

Both functional and class components can be typed to get the benefits of strongly typed options and props.

<Tabs
  defaultValue="clazz"
  values={[
    { label: 'Class Component', value: 'clazz' },
    { label: 'Functional Component', value: 'functional' },
  ]}
>

<TabItem value="clazz">

```tsx file=./third-party-typescript/strongly-typed-components-class.tsx
```

</TabItem>

<TabItem value="functional">

```tsx file=./third-party-typescript/strongly-typed-components-fn.tsx
```

</TabItem>

</Tabs>

## Typed props in commands

Arguments are passed to components view the `passProp`. This is a common source for errors as these props tend to change overtime. Luckily we can type the passProps property to avoid these regressions. The example below shows how to declare types for passProps when pushing a screen.

```tsx file=./third-party-typescript/typed-props-in-commands.tsx
```

The following commands accept typed passProps:

- push
- setStackRoot
- showModal
- showOverlay

---

### Website Versioned Docs Version 7.11.2 Docs Community Libraries (`website/versioned_docs/version-7.11.2/docs/community-libraries.mdx`)

---
id: community-libraries
title: Community libraries
sidebar_label: Community libraries
---

React Native Navigation has an active community with a bunch of support libraries.

[React Native Navigation Hooks](https://github.com/underscopeio/react-native-navigation-hooks) :
A set of React hooks for React Native Navigation.

[React Native Navigation Drawer Extension](https://github.com/lukebrandonfarrell/react-native-navigation-drawer-extension) :
Drawer API built on top of React Native Navigation for iOS and Android. 

[React Native Navigation Search Bar](https://github.com/lukebrandonfarrell/react-native-navigation-search-bar) :
React Native Elements search bar with collapsible header built for React Native Navigation.

[React Native Navigation Register Screens](https://github.com/karlmarxlopez/react-native-navigation-register-screens) : 
Utility function to register array of screens instead of calling `Navigation.registerComponent` multiple times.

---

### Website Versioned Docs Version 7.11.2 Docs Docs Installing (`website/versioned_docs/version-7.11.2/docs/docs-Installing.mdx`)

---
id: installing
title: Installation
sidebar_label: Installation
---

## Requirements

- node >= 8
- react-native >= 0.51

## npm or yarn

npm:

```sh
npm install --save react-native-navigation
```

yarn:

```sh
yarn add react-native-navigation
```

## Installing with `npx rnn-link`

If you're using RN 0.60 or higher, you can benefit from autolinking for some of the necessary installation steps. But unlike most other libraries, react-native-navigation requires you to make a few changes to native files.

We've simplified the process through a set of scripts. So to make all the necessary changes automatically, in your project's root folder run:

`npx rnn-link`

Make sure to commit the changes introduced by the `rnn-link` script.

> The automatic linking is optimized for new applications created via the `react-native init` command. If you are migrating from a version of react-native-navigation older than v5, it's recommended to check the steps manually after the script runs.

If one of the steps failed or you can't run (or are not comfortable with) the automatic scripts, you'll need to complete the relevant steps in the manual installation steps below, for both platforms.

### CocoaPods

After the the automatic scripts completed successfully, run pod install:

```sh
pod install --project-directory=ios
```

### Update index.js file

`index.js` is typically used as an entry point into the app. It's first parsed and executed by the JS engine, therefore we'll want to show our UI from there.

The following diff demonstrates changes needed to be made to `index.js`, initialized by `react-native init`.

```diff
+import { Navigation } from "react-native-navigation";
-import {AppRegistry} from 'react-native';
import App from "./App";
-import {name as appName} from './app.json';

-AppRegistry.registerComponent(appName, () => App);
+Navigation.registerComponent('com.myApp.WelcomeScreen', () => App);

+Navigation.events().registerAppLaunchedListener(() => {
+   Navigation.setRoot({
+     root: {
+       stack: {
+         children: [
+           {
+             component: {
+               name: 'com.myApp.WelcomeScreen'
+             }
+           }
+         ]
+       }
+     }
+  });
+});
```

### Finish

If you followed the steps successfully up to this point, then rebuild your application and you are good to go:

```sh
react-native run-ios
react-native run-android
```

:::tip
This is a good moment to build your application in both platforms, validate that everything is working properly and commit your changes. If you're coming from a fresh `react-native init` project, then you should be seeing the Welcome screen as usual, but under the hood your application is using react-native-navigation!
::::

---

## Manual Installation

If installation with `npx rnn-link` did not work, follow the manual installation steps below.

### iOS

> Make sure your Xcode is updated. We recommend editing `.h` and `.m` files in Xcode as the IDE will usually point out common errors.

#### Installation with CocoaPods

Projects generated using newer versions of react-native use CocoaPods by default. In that case it's easier to install react-native-navigation using CocoaPods.

1. Update your `Podfile`:
   **If you're upgrading to v5 from a previous RNN version**, make sure to remove manual linking of RNN

```
/* Detailed source-code truncated for AI context efficiency. */
```

2. `cd ios && pod install`

#### Native Installation

> If the React Native version in your project is above 0.60 and you are following the manual installation, skip to step 3.

If autolinking is not available in your project (RN version < 0.60), you can always try and install the hardcore way:

1. In Xcode, in Project Navigator (left pane), right-click on the `Libraries` > `Add files to [project name]`. Add `node_modules/react-native-navigation/lib/ios/ReactNativeNavigation.xcodeproj` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking)).

2. In Xcode, in Project Navigator (left pane), click on your project (top), then click on your _target_ row (on the "project and targets list", which is on the left column of the right pane) and select the `Build Phases` tab (right pane). In the `Link Binary With Libraries` section add `libReactNativeNavigation.a` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-2)).

a. If you're seeing an error message in Xcode such as:

```
'ReactNativeNavigation/ReactNativeNavigation.h' file not found.
```

You may also need to add a Header Search Path: ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-3)).

```objectivec
$(SRCROOT)/../node_modules/react-native-navigation/lib/ios
```

3. In Xcode, you will need to edit this file: `AppDelegate.m`. This function is the main entry point for your app:

```objectivec
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... }
```

Its content should look like this:

```objectivec
#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <ReactNativeNavigation/ReactNativeNavigation.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [ReactNativeNavigation bootstrapWithDelegate:self launchOptions:launchOptions];

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  #if DEBUG
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
  #endif
}

- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge {
  return [ReactNativeNavigation extraModulesForBridge:bridge];
}

@end
```

    a. If, in Xcode, you see the following error message in `AppDelegate.m` next to `#import "RCTBundleURLProvider.h"`:
    ```
    ! 'RCTBundleURLProvider.h' file not found
    ```
    This is because the `React` scheme is missing from your project. You can verify this by opening the `Product` menu and the `Scheme` submenu.
    To make the `React` scheme available to your project, run `npm install react-native-git-upgrade` followed by `react-native-git-upgrade`. Once this is done, you can click back to the menu in Xcode: `Product -> Scheme -> Manage Schemes`, then click '+' to add a new scheme. From the `Target` menu, select "React", and click the checkbox to make the scheme `shared`. This should make the error disappear.

### Android

> Make sure your Android Studio installation is up to date. We recommend editing `gradle` and `java` files in Android Studio as the IDE will suggest fixes and point out errors, this way you avoid most common pitfalls.

#### 1 Update `android/build.gradle`:

```diff
buildscript {
  ext {
-   minSdkVersion = 16
+   minSdkVersion = 21 // Or higher
    compileSdkVersion = 26
    targetSdkVersion = 26
    supportLibVersion = "26.1.0"
+   kotlinVersion = "1.3.72" // Or any version above 1.3.x
+   RNNKotlinVersion = kotlinVersion
  }
  repositories {
        google()
        jcenter()
+        mavenLocal()
+        mavenCentral()
  }
  dependencies {
+        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
+        classpath 'com.android.tools.build:gradle:3.5.3' // Or higher
-        classpath 'com.android.tools.build:gradle:2.2.3'
  }
}

allprojects {
  repositories {
+   google()
    mavenLocal()
    jcenter()
    maven {
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
      url "$rootDir/../node_modules/react-native/android"
    }
-        maven {
-            url 'https://maven.google.com/'
-            name 'Google'
-        }
+   maven { url 'https://jitpack.io' }
  }
}
```

#### 2 Update `MainActivity.java`

`MainActivity.java` should extend `com.reactnativenavigation.NavigationActivity` instead of `ReactActivity`.

This file is located in `android/app/src/main/java/com/<yourproject>/MainActivity.java`.

```diff
-import com.facebook.react.ReactActivity;
+import com.reactnativenavigation.NavigationActivity;

-public class MainActivity extends ReactActivity {
+public class MainActivity extends NavigationActivity {
-    @Override
-    protected String getMainComponentName() {
-        return "yourproject";
-    }
}
```

If you have any **react-native** related methods, you can safely delete them.

#### 3 Update `MainApplication.java`

This file is located in `android/app/src/main/java/com/<yourproject>/MainApplication.java`.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### App root

Now that you're done, don't forget to update the `index.js` file, as [shown above](#update-indexjs-file).

## Troubleshooting

### Build app with gradle command

**prefered solution** - The RNN flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .

```
"scripts": {
  ...
  "android": "cd ./android && ./gradlew app:assembleDebug && ./gradlew installDebug"
}
```

Now run `npm run android` to build your application

### Force the same support library version across all dependencies

Some of your dependencies might require a different version of one of Google's support library packages. This results in compilation errors similar to this:

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:preDebugBuild'.
> Android dependency 'com.android.support:design' has different version for the compile (25.4.0) and runtime (26.1.0) classpath. You should manually set the same version via DependencyResolution
```

To resolve these conflicts, add the following to your `app/build.gradle`:

```groovy
android {
    ...
}

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support' && requested.name != 'multidex') {
            details.useVersion "${rootProject.ext.supportLibVersion}"
        }
    }
}

dependencies {
    ...
    implementation 'com.android.support:design:25.4.0'
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
}

```

---

### Website Versioned Docs Version 7.11.2 Docs Docs Advanced Navigation (`website/versioned_docs/version-7.11.2/docs/docs-advanced-navigation.mdx`)

---
id: advanced-navigation
title: Advanced navigation
sidebar_label: Advanced navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

## Tab navigation

As mobile applications become bigger and more complex, they usually end up containing multiple primary high-level destinations, which are logically independent from one another. The `BottomTabs` layout is often used when an app contains three to five top-level destinations which should be accessible from anywhere in the app.

Lets return to the example code from the previous section ([Basic navigation](basic-navigation)) and see how we can convert it to a tab-based application. We'll use the BottomTabs layout to display tabs at the bottom of the screen. Similarly to `Stack` layout, The BottomTabs layout also contains a `children` property where each child will be displayed in a tab.

Lets change our code to the following and reload the app.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Now our app has two tabs at the bottom of the screen and our users can easily navigate between them.

<img width="40%" src={useBaseUrl('img/stack4.png')} />

## Replacing the root

Up until now, we've discussed how to navigate within the same layout structure. We'll now learn how to replace the entire layout structure to display a new Root. A real life example for this use case would be, for instance, if you need to switch from a login screen to the app's main root. Replacing the root fits this use case since we'd like to discard the previous root (login root) entirely when switching to the main root.

To demonstrate this, we'll make the following changes to our code:

1. Add a login screen with a login button.
2. When the button is clicked, we will switch to the main root.
3. Replace our current root with the login screen. We'll also extract both roots to variables to improve code readability.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Conditional roots

Now that our initial root is the Login root, we're facing a new problem - how do we show the Login root only to users that are not logged in? Since our initial root is determined in the `registerAppLaunchedListener` callback, we'll check if a user is logged in there and set the appropriate root accordingly.

```jsx
Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot(isLoggedIn() ? mainRoot : loginRoot);
});

function isLoggedIn() {
  // TODO: your business logic goes here
}
```

---

### Website Versioned Docs Version 7.11.2 Docs Docs App Launch (`website/versioned_docs/version-7.11.2/docs/docs-app-launch.mdx`)

---
id: app-launch
title: Launching the app
sidebar_label: Launching the app
---

When your app is launched for the first time, the bundle is parsed and executed. At this point you need to display your UI. To do so, listen to the `appLaunched` event and call `Navigation.setRoot` when that event is received.

```js
Navigation.events().registerAppLaunchedListener(() => {
  // Each time the event is received you should call Navigation.setRoot
});
```

:::important
Register the app launched listener as soon as possible - this should be one of the first lines in your `index.js` file.
:::

If you're observing a "white screen" or a hanging splash screen after relaunching your app, it probably means `Navigation.setRoot` isn't called as soon as the app is launched. Perhaps the listener was registered too late.

## Difference between the platforms
When your app is launched, RN makes sure JS context (which is what enables you to execute JavaScript code) is running. There are quite a few differences between iOS and Android in this regard.

### iOS
Whenever an app is put into the background, the app process can potentially be destroyed by the system. If this destruction takes place, the JS context will be destroyed alongside with the app process.

### Android
An Android application is typically bound to two contexts:

1. Application context - bound to the app process
1. Activity context - bound to app UI

React's JS Context is executed on and bound to the Application context. This means that even when the Activity context (and thus the UI) is destroyed, React's JS Context remains active until the Application (and your process) are destroyed by the system.

:::caution
Because of this, when your app returns to foreground, JS Context might still exist on Android, even when the Activity and UI contexts have been destroyed - meaning you might not need to initialise all of your app logic; instead, you'll only need to call `Navigation.setRoot` to repopulate the UI context. This circumstance can easily be determined by setting a flag on your app's first `appLaunched` event, and checking the value of that flag on subsequent `appLaunched` events -- if the flag is true in your `appLaunched` callback, you need to call `Navigation.setRoot` to repopulate the UI.
:::

---

### Website Versioned Docs Version 7.11.2 Docs Docs Basic Navigation (`website/versioned_docs/version-7.11.2/docs/docs-basic-navigation.mdx`)

---
id: basic-navigation
title: Basic navigation
sidebar_label: Basic navigation
---

import useBaseUrl from '@docusaurus/useBaseUrl';

Generally, any mobile app consists of various destinations which display some content to the user. And in vast majority of cases using an app means navigating between these destinations. React-native-navigation provides ways for you to layout your content on user screen in a logical and performant manner.

React Native Navigation's stack layout lets you push screens, and also navigate back to previous screens. Screens pushed into the stack hide the previous screen in the stack, making the user focus on a single screen at a time. Let's look at a stack layout that provides basic navigation for an app.

## Creating a stack

```jsx
// In index.js of a new project
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { Navigation } from 'react-native-navigation';

const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Home Screen</Text>
    </View>
  );
};
Navigation.registerComponent('Home', () => HomeScreen);

Navigation.events().registerAppLaunchedListener(async () => {
  Navigation.setRoot({
    root: {
      stack: {
        children: [
          {
            component: {
              name: 'Home'
            }
          }
        ]
      }
    }
  });
});

const styles = StyleSheet.create({
  root: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'whitesmoke'
  }
});
```

Running this code will render a screen with an empty TopBar and your HomeScreen component (shown below). The TopBar is part of the stack layout, we'll work on configuring it later.

<img width="40%" src={useBaseUrl('img/stack1.png')} />

## Specifying options

You can specify options of each layout (Stack, component pushed into a stack, etc.) to configure various parameters like the TopBar title or color. Lets spice things up by changing the TopBar color and while we're at it, also move the title to the TopBar.

Lets change the Home screen declaration to the following and reload the app to see the changes.
```jsx
const HomeScreen = (props) => {
  return (
    <View style={styles.root}>
      <Text>Hello React Native Navigation 👋</Text>
    </View>
  );
};
HomeScreen.options = {
  topBar: {
    title: {
      text: 'Home',
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
}
```

Our app should now look like this:
<img width="40%" src={useBaseUrl('img/stackOptions.png')} />

## Navigating in a stack

In the previous section we created a stack and initialized it with a single child. We'll now learn how to add another child to the stack. From now on, we'll call the action of adding children to the stack 'push', and removing children - 'pop'.

In order to push another screen to the stack, we will add a button to the home screen and call `Navigation.push`. The 'push' command accepts two parameters, the first is the id used to indicate into which stack to push the screen and the second is the screen we're pushing. After pushing a screen, a back button is added automatically to the TopBar so the users can navigate easily back to the previous screen.

You can read more about the stack layout [here](docs-stack.mdx) or dive right into the API [here](../api/layout-stack).

:::info componentId
Each React component registered with `Navigation.registerComponent` is assigned a unique `componentId` by Navigation. This unique id is used with Navigation commands (like the push command) to indicate into which stack we'd like to push. In this case, by using the componentId of the Home screen, we are telling Navigation to push into the stack containing the Home screen.
:::

```js
Navigation.push(props.componentId, {
  component: {
    name: 'Settings', // Push the screen registered with the 'Settings' key
    options: { // Optional options object to configure the screen
      topBar: {
        title: {
          text: 'Settings' // Set the TopBar title of the new Screen
        }
      }
    }
  }
});
```

Lets change our code to the following snippet below and reload the app. Now our Home should contain a button which when pressed, pushes a new screen into the stack. We've successfully navigated to a new screen! 👏

```
/* Detailed source-code truncated for AI context efficiency. */
```

<img width="40%" src={useBaseUrl('img/stack2.gif')} />

## App theme

Our app is growing and already contains two screens. This introduces a new problem - while the home screen has a nice purple TopBar, our settings screen seems pretty dull as it still uses the default system look and feel.

Currently, our style declaration applies only to the Home screen, so lets apply it to all of our screens by using `Navigation.setDefaultOptions`.

```js
Navigation.setDefaultOptions({
  statusBar: {
    backgroundColor: '#4d089a'
  },
  topBar: {
    title: {
      color: 'white'
    },
    backButton: {
      color: 'white'
    },
    background: {
      color: '#4d089a'
    }
  }
});
```

We need to add this snippet before registering the `registerAppLaunchedListener`. This way we ensure our theme is applied when our root is set. Our code should now look like this:

```
/* Detailed source-code truncated for AI context efficiency. */
```

Lets run our code again - now our design is consistent across both screens.

<img width="40%" src={useBaseUrl('img/stack3.gif')} />

## Summary

We've learned the basics of navigation with React Native Navigation by implementing a stack and pushing screens into it.
We've also learned a few methods of applying styles to our screens and layouts with the Options mechanism.

* Navigation.setRoot() sets the root layout of our app. The initial root has to be set from an `AppLaunchedEvent` callback.
* Options can be applied directly to components.
* Screens can be added to a stack with the `Navigation.push()` command.
* Components registered with `Navigation.registerComponent()` are injected with a `componentId` which is used when navigating.
* Themes are applied via the `Navigation.setDefaultOptions()` command.

In the next section we'll explore a more advance navigation patterns using BottomTabs layout and also see how, and why, multiple roots are set.

---

### Website Versioned Docs Version 7.11.2 Docs Docs Before You Start (`website/versioned_docs/version-7.11.2/docs/docs-before-you-start.mdx`)

---
id: before-you-start
title: Before you start
sidebar_label: Before you start
---

React Native Navigation is a module, dependent on and intended to be used alongside [React Native](https://github.com/facebook/react-native), so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their [getting started](https://reactnative.dev/docs/getting-started) tutorial, and then come back here when you're ready.

We also assume you are working on a Mac with XCode and Android Studio installed and setup. You can also make it work in a Linux distribution, of course, but in that case bear in mind that some sections of the docs that deal with iOS might not be relevant to you.

If you want to dig right into it, start with [installing](docs-Installing.mdx) the library. If you're just looking around, we suggest checking out [basic navigation](docs-basic-navigation.mdx) first.

---

### Website Versioned Docs Version 7.11.2 Docs Docs BottomTabs (`website/versioned_docs/version-7.11.2/docs/docs-bottomTabs.mdx`)

---
id: bottomTabs
title: Bottom tabs
sidebar_label: Bottom tabs
---
import useBaseUrl from '@docusaurus/useBaseUrl';

Bottom tabs refers to a row of links, displayed at the bottom of the screen, and is referred to as "Tab Bar" in iOS and as "Bottom Navigation Bar" on Android. Usually these are intended to be used to switch between top-level content views with a single tap.

## Creating bottom tabs

BottomTabs provide flat navigation and access to up to five equally important top-level root destinations. While any type of layout can be displayed in a tab, typically, [Stacks](stack) are used, since they allow for vertical navigation within a tab.

### Example
Lets see how to create a simple BottomTabs layout. There are a few things to notice here:
1. Each child represents a tab on the screen.
2. The root layout for each tab is a stack to allow for vertical navigation within the tab.
3. Each stack declares `bottomTab` options which are used to configure the tab's text, icon, color etc.

```js
bottomTabs: {
  id: 'BOTTOM_TABS_LAYOUT',
  children: [
    {
      stack: {
        id: 'HOME_TAB',
        children: [
          {
            component: {
              id: 'HOME_SCREEN',
              name: 'HomeScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./home.png')
          }
        }
      }
    },
    {
      stack: {
        id: 'PROFILE_TAB',
        children: [
          {
            component: {
              id: 'PROFILE_SCREEN',
              name: 'ProfileScreen'
            }
          }
        ],
        options: {
          bottomTab: {
            icon: require('./profile.png')
          }
        }
      }
    }
  ]
}
```

Once we run this code, our BottomTabs should look like this:
<img width="40%" src={useBaseUrl('img/bottomTabs.png')} />

## Selecting Tabs Programmatically
Tabs can be selected programmatically by updating the `currentTabIndex` or `currentTabId` options.

We'll use the BottomTabs layout showcased [above](bottomTabs#example) to demonstrate programmatic tab selection.

### Selecting a tab by index
The following mergeOptions command will select the second tab. We're passing the id of our BottomTabs layout, but we could also use the id of any of the child components, for example `PROFILE_TAB` or `PROFILE_SCREEN`.

```js
Navigation.mergeOptions('BOTTOM_TABS_LAYOUT', {
  bottomTabs: {
    currentTabIndex: 1
  }
});
```

### Selecting a tab by id
Tabs can also be selected by id (`componentId`). This is particularly useful in cases where you don't know in which tab a screen is contained.
For example, if invoked from one of the child components, `HOME_SCREEN` or `SETTINGS_SCREEN`, the following merge command will select the tab containing the child.

```js
Navigation.mergeOptions(this.props.componentId, {
  bottomTabs: {
    currentTabId: this.props.componentId
  }
});
```

## Changing BottomTabs visibility

The `visible` property is used to control the BottomTab visibility. Visibility can be toggled dynamically using the `mergeOptions` command.
```js
Navigation.mergeOptions(componentId, {
  bottomTabs: {
    visible: false
  },
});
```

Visibility can also be changed when pushing screens.
```js
Navigation.push(componentId, {
  component: {
    name: 'pushedScreen',
    options: {
      bottomTabs: {
        visible: false
      }
    }
  }
});
```

## Updating tab options dynamically

To update a tab option, like an icon, text or color, simply call `mergeOptions` with new options using the id of a component or layout contained in the tab you wish to update.

For instance, in the example below we update the color of a specific tab:
```js
Navigation.mergeOptions(componentId, {
  bottomTab: {
    iconColor: 'red',
    textColor: 'red'
  },
});
```

## Controlling tab loading

By default, all tabs are mounted at the same time. This can have a negative impact on performance since screens which are not visible to the user are mounted.

The order in which tabs are mounted can be configured with the `tabsAttachMode` option:

* `together` - all tabs are mounted at the same time, this is the default behavior.
* `afterInitialTab` - after initial tab is mounted, other tabs are mounted.
* `onSwitchToTab` - initial tab is mounted, other tabs are mounted when the user navigates to them for the first time.

---

### Website Versioned Docs Version 7.11.2 Docs Docs ExternalComponent (`website/versioned_docs/version-7.11.2/docs/docs-externalComponent.mdx`)

---
id: externalComponent
title: External Component
sidebar_label: External Component
---

The ExternalComponent layout allows you to display any native view as a screen. To use the External Component we'll need to register it with a string name. This name is then used when declaring layouts in JS.

## Android
### Implementing the native component
When it comes to implementing an external component on Android, you have two choices. We recommend you use a base class extending `View`. If you're required to use Fragments, you'll find an basic example below.

#### ViewGroup
```java
public class ViewGroupComponent implements ExternalComponent {
    private final FrameLayout content;

    ViewGroupComponent(FragmentActivity activity, JSONObject props) {
        content = new FrameLayout(activity);
    }

    @Override
    public View asView() {
        return content;
    }
}
```

#### Fragment

Using a Fragment as an external component is done by attaching the Fragment to a FrameLayout, and returning the FrameLayout from the `asView()` method of the ExternalComponent.

```java
public class FragmentComponent implements ExternalComponent {
    private final FrameLayout content;

    FragmentComponent(FragmentActivity activity, JSONObject props) {
        // Create the FrameLayout to which we'll attach our Fragment to
        content = new FrameLayout(activity);
        content.setId(R.id.fragment_screen_content);
        // Attach the Fragment to the FrameLayout
        activity.getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_screen_content, createFragment(props))
                .commitAllowingStateLoss();
    }

    private FragmentScreen createFragment(JSONObject props) {
        FragmentScreen fragment = new FragmentScreen();
        // Pass the props sent from Js in a bundle
        Bundle args = new Bundle();
        args.putString("text", props.optString("text", ""));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View asView() {
        return content;
    }
}
```

### Registering the component
```java
public class MainApplication extends NavigationApplication {
  @Override
    public void onCreate() {
        super.onCreate();
        registerExternalComponent("MyExternalComponent", new FragmentCreator());
    }
}
```

## iOS
### ViewController registration

```objectivec
[ReactNativeNavigation registerExternalComponent:@"MyExternalComponent" callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) {
	return [[ExternalViewController alloc] initWithProps:props];
}];

```
## Using the component from JS
Once you've registered the external component in native, you can use it in your layout declarations.
For example, to show an external component modally:
```js
Navigation.showModal({
  externalComponent: {
    name: 'MyExternalComponent',
    passProps: {
      text: "Text from JS"
    }
  }
});
```

:::caution
props passed to external components are sent over the bridge and therefore must be serializable.
:::

---

### Website Versioned Docs Version 7.11.2 Docs Docs Functional Components (`website/versioned_docs/version-7.11.2/docs/docs-functional-components.mdx`)

---
id: functionalComponents
title: Using functional components as screens
sidebar_label: Using functional components
---

Both class components and functional components can be used as screens. There is no performance difference between the two. Deciding which type component to use boils down to user preference.

## Declaring static options
Static options are a great way to declare options close to where they are used. Declaring static options is done by first declaring the functional component, and then declaring the options on the function component.
```jsx
const MyScreen = (props) => {
  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
};

MyScreen.options = {
  topBar: {
    background: {
      color: 'red'
    }
  }
}
```

## Listening to navigation events
Navigation events let you react to various events related to a specific component or the app itself. Read more about them [here](/react-native-navigation/api/events)

```jsx
import { useEffect } from 'react';
import Navigation from 'react-native-navigation';

function MyScreen(props) {
  useEffect(() => {
    const listener = {
      componentDidAppear: () => {
        console.log('RNN', `componentDidAppear`);
      },
      componentDidDisappear: () => {
        console.log('RNN', `componentDidDisappear`);
      }
    };
    // Register the listener to all events related to our component
    const unsubscribe = Navigation.events().registerComponentListener(listener, props.componentId);
    return () => {
      // Make sure to unregister the listener during cleanup
      unsubscribe.remove();
    };
  }, []);

  return (
      <View>
        <Text>Screen Component</Text>
      </View>
    );
}
```

In the example above, our listener is registered with the `componentId` passed in the second argument, and will receive only its related events.

:::tip
[underscopeio/react-native-navigation-hooks](https://github.com/underscopeio/react-native-navigation-hooks) is a wonderful library which greatly simplifies usage with hooks by introducing dedicated hooks for each event. The following example, which is taken from their docs, shows how to listen to all appear events and a particular screen's appear events:

```jsx
import { useNavigationComponentDidAppear } from 'react-native-navigation-hooks'

const ScreenComponent = ({ componentId }) => {
  // Global listener
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} (${e.componentId}) appeared`)
  })

  // Listen events only for this screen (componentId)
  useNavigationComponentDidAppear(e => {
    console.log(`${e.componentName} appeared`)
  }, componentId)

  return (
    <View>
      <Text>Screen Component</Text>
    </View>
  )
}
```
:::

---

### Website Versioned Docs Version 7.11.2 Docs Docs Modal (`website/versioned_docs/version-7.11.2/docs/docs-modal.mdx`)

---
id: modal
title: Modal
sidebar_label: Modal
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

In human-centered design, when we speak about a modal (or modality), we often refer to a set of techniques, aimed at bringing user attention to a specific event / screen / action / etc. Those often require user input. A pop-up on a website, a file deletion confirmation dialogue on your computer, or an alert asking you to enable location service on your phone - these can all be considered modals.

A modal is a term used in native iOS world ([full description here](https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/)), while on Android, [dialogs](https://developer.android.com/guide/topics/ui/dialogs) are often used to create similar or identical behavior, alongside other techniques.

## Presenting modals

Modal can be displayed by invoking the `Navigation.showModal()` command, as shown in the example below:

```js
Navigation.showModal({
  stack: {
    children: [
      {
        component: {
          name: 'MODAL_SCREEN',
          options: {
            topBar: {
              title: {
                text: 'Modal',
              },
            },
          },
        },
      },
    ],
  },
});
```

Here's how the Modal looks on both platforms.

<Tabs
  defaultValue="ios"
  values={[
    { label: 'iOS', value: 'ios' },
    { label: 'Android', value: 'android' },
  ]}
>
  <TabItem value="ios">
    <img width="40%" src={useBaseUrl('img/modal_ios.gif')} />
  </TabItem>
  <TabItem value="android">
    <img width="40%" src={useBaseUrl('img/modal_android.gif')} />
  </TabItem>
</Tabs>

## Adding a dismiss button

Modals should always have a dismiss button, on left-to-right devices it's typically placed as a left button in the TopBar.

After we've added our dismiss button, we need to dismiss the modal when the button is pressed.

:::note
For the LeftButton to be visible, the screen must be displayed in a Stack.
:::

```js
class ModalScreen extends React.Component {
  // Set a dismiss button in static options
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'dismiss',
          icon: require('./dismiss.png'),
        },
      },
    };
  }

  constructor(props) {
    super(props);
    // Register to events
    Navigation.events().bindComponent(this);
  }

  // Handle the button press event and dismiss the modal if needed
  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'dismiss') {
      Navigation.dismissModal(this.props.componentId);
    }
  }
}
```

## Transparent modals

Showing transparent modals is a nice technique to increase immersiveness while keeping the user in the same context.
When a modal is displayed the content behind it (either root or modal) is removed from hierarchy. While this behavior improves performance, it's undesired when
showing transparent modals as we need to see the content behind it.

To configure this behaviour, we'll need to change the `modalPresentationStyle` option to `overCurrentContext` and change the layout background color to `'transparent'`.

```js
{
  modalPresentationStyle: 'overCurrentContext',
  layout: {
    backgroundColor: 'transparent'
  }
}
```

## Preventing a Modal from being dismissed

Preventing a modal from being dismissed is done differently for each platform. While preventing the user from dismissing the modal is possible,
the modal could still be dismissed programmatically by calling `Navigation.dismissModal()`

If the modal has a dismiss button, of course you'll need to handle it your self and avoid calling `Navigation.dismissModal()`
when the button is pressed.

### Android

On Android, modals can be dismissed with the hardware back button. You can handle the back press yourself by
disabling the hardware back button `dismissModalOnPress` option:

```js
{
  hardwareBackButton: {
    dismissModalOnPress: false;
  }
}
```

As a result, pressing the hardware back button will not dismiss the modal and will dispatch [`navigationButtonPress`](https://wix.github.io/react-native-navigation/api/events#navigationbuttonpressed-event) event with the default hardware back button id `RNN.hardwareBackButton`.

### iOS

While iOS devices don't have a hardware back button, PageSheet modals can be dismissed by swipe gesture
from the top of the screen. To disable it, set [swipeToDismiss](#) option to false.

## Presentation Style

The [presentation style](/react-native-navigation/api/options-root#modalpresentationstyle) determines the look and feel of a screen displayed as modal.

---

### Website Versioned Docs Version 7.11.2 Docs Docs Overlay (`website/versioned_docs/version-7.11.2/docs/docs-overlay.mdx`)

---
id: overlay
title: Overlay
sidebar_label: Overlay
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Overlays are used to layout content on top of all other layout hierarchies, while fitting the screen bounds.
The contents displayed in an Overlay can either be non-obtrusive, like Toasts and Snackbars, or an Alert that blocks all interactions with any content behind it. The view contained within it should be aligned either with absolute position, flex, or with margins, all according to your needs.

## Handling touch events outside the view

When showing views like Alert or Toast in an Overlay, you would want to configure if you want to allow users to interact with content behind the alert. This is done via the [interceptTouchOutside](#) option.

## Overlay examples

<Tabs
  defaultValue="alert"
  values={[
    { label: 'Alert', value: 'alert', },
    { label: 'Toast', value: 'toast', }
  ]
}>
<TabItem value='alert'>

The example below demonstrates how to create a simple alert dialog using an Overlay. Touch events outside the alert will be blocked and won't pass through to the content behind the alert since we're specifying `interceptTouchOutside: true` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/alert_android.png')} />

```jsx
const React = require('react');
const { Text, Button, View } = require('react-native');
const { Navigation } = require('react-native-navigation');

function Alert({ componentId, title, message }) {
  const dismiss = () => Navigation.dismissOverlay(componentId);

  return (
    <View style={styles.root}>
      <View style={styles.alert}>
        <Text style={styles.title}>{title}</Text>
        <Text style={styles.message}>{message}</Text>
        <Button title="OK" onPress={dismiss} />
      </View>
    </View>
  );
}

const styles = {
  root: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#00000050',
  },
  alert: {
    alignItems: 'center',
    backgroundColor: 'whitesmoke',
    width: 250,
    elevation: 4,
    padding: 16,
  },
  title: {
    fontSize: 18,
  },
  message: {
    marginVertical: 8,
  },
};

Alert.options = (props) => {
  return {
    overlay: {
      interceptTouchOutside: true,
    },
  };
};

module.exports = Alert;
```

</TabItem>
<TabItem value='toast'>

The example below demonstrates how to show a Toast using an Overlay. A user can interact with the content behind the toast since we've declared `interceptTouchOutside: false` in the static options of the Alert.

<img width="30%" src={useBaseUrl('/img/toast_android.png')} />

```jsx
const React = require('react');
const { View, Text, StyleSheet, TouchableOpacity } = require('react-native');
const Colors = require('../commons/Colors');
const Navigation = require('../services/Navigation');

const Toast = function ({ componentId }) {
  return (
    <View style={styles.root}>
      <View style={styles.toast}>
        <Text style={styles.text}>This a very important message!</Text>
        <TouchableOpacity
          style={styles.button}
          onPress={() => Navigation.dismissOverlay(componentId)}
        >
          <Text style={styles.buttonText}>OK</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  root: {
    flex: 1,
    flexDirection: 'column-reverse',
  },
  toast: {
    elevation: 2,
    flexDirection: 'row',
    height: 40,
    margin: 16,
    borderRadius: 20,
    backgroundColor: Colors.accent,
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  text: {
    color: 'white',
    fontSize: 16,
    marginLeft: 16,
  },
  button: {
    marginRight: 16,
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
});

Toast.options = {
  layout: {
    componentBackgroundColor: 'transparent',
  },
  overlay: {
    interceptTouchOutside: false,
  },
};

module.exports = Toast;
```

</TabItem>
</Tabs>

---

### Website Versioned Docs Version 7.11.2 Docs Docs Passing Data To Components (`website/versioned_docs/version-7.11.2/docs/docs-passing-data-to-components.mdx`)

---
id: passing-data-to-components
title: Passing data to components
sidebar_label: Passing data to components
---

## Initial props

React components use [props](https://facebook.github.io/react-native/docs/props) to receive data when they are created. When displaying the [component](../api/layout-component) layout, you can pass initial props to components using the `passProps` property.

In this example, we push the `UserProfile` screen and pass two initial props to it:

```js
Navigation.push(this.props.componentId, {
  component: {
    name: 'UserProfile',
    id: 'PROFILE_SCREEN_ID'
    passProps: {
      name: 'John Doe',
      status: 'online'
    }
  }
});
```

:::tip Serialization
passProps don't need to be serializable. You can use this mechanism to pass lambda functions or even React Components.
:::

## Handling passProps in static options

Each component can have a static options property which is used to configure the style properties of elements on the screen when that component is displayed. 

Static options can either be a simple object, or a function which accepts `passProps` as an argument. Sometimes when declaring components, not all style properties are known. For example, a user profile screen will usually have the user's name as the TopBar title text. Therefore the title must be configured dynamically when pushing the screen.

Following the code example [above](passing-data-to-components#initial-props), lets see how to use props passed in the push command to set the TopBar title.

```jsx
class UserProfileScreen extends React.Component {
  static options(props) {
    return {
      topBar: {
        title: {
          text: props.name
        }
      }
    };
  }
}
```

## Updating props

To update a component's props, use the [Navigation.updateProps()](../api/component#updateprops) command. Updating props triggers the component lifecycle methods related to [updating](https://reactjs.org/docs/react-component.html#updating).

Notice that we're using the component `id` in order to update props of this specific instance of the component.

```js
Navigation.updateProps('PROFILE_SCREEN_ID', {
  status: 'offline'
});
```

---

### Website Versioned Docs Version 7.11.2 Docs Docs Playground App (`website/versioned_docs/version-7.11.2/docs/docs-playground-app.mdx`)

---
id: playground-app
title: Playground app
sidebar_label: Playground app
---

### Running The Project

If you want to have a quick look around and test things out, you can run the playground app, bundled with this repo.

1. Install dependencies via `npm install` (if you haven't already) and `npm run pod-install` (for iOS)
2. Run the playground project on Android and iOS
    - `npm run start` to get the packager running in the terminal, leave it open
    - **iOS**: open `./playground/ios` in Xcode and run it
    - **Android**: open `./playground/android` in Android Studio and run it
3. You can run tests if / when you need to (list of scripts [available here](meta-contributing#scripts)). Before
you start changing things, make sure everything works.
	- To easily run all tests in parallel `npm run test-all`

---

### Website Versioned Docs Version 7.11.2 Docs Docs Root (`website/versioned_docs/version-7.11.2/docs/docs-root.mdx`)

---
id: root
title: Root
sidebar_label: Root
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

The root is where the application layout structure is defined. It is typically the first UI element a user interacts with. The root can be changed multiple times during the lifespan of the application. For example, if an app requires users to login, it's common to use a stack-based root and transition to either tabs- or SideMenu-based root if login is successful.

## Setting root on app launch
RNN exposes an appLaunched listener which is invoked whenever root needs to be set.

On iOS, the app launched event is usually emitted once in the lifespan of the application - when the app is opened for the first time. On Android things become a little bit more complicated. Like on iOS, the event is emitted when an app is opened for the first time. Since the system can destroy the Activity when the app is in the background to free resources, the event is emitted when the app returns to foreground after the activity has been destroyed.

```js
Navigation.events().registerAppLaunchedListener(() => {
  Navigation.setRoot({
    root: {

    }
  });
});
```

:::important
registerAppLaunchedListener() must be called as soon as the bundle is executed. Otherwise the event, which is emitted from native to JS, won't be handled at the correct moment in time.
::::

## Conditional initial root
A common use case is to set the initial root according to a condition of some sort. For example:

> If a user is logged in, show the application main root; otherwise show a login screen.

To do this, simply set the appropriate root according to your needs.
```js
Navigation.events().registerAppLaunchedListener(() => {
  if (isUserLoggedIn()) {
    setMainRoot();
  } else {
    setLoginRoot();
  }
});
```

## Common root structures

<Tabs
  defaultValue='stack'
  values={[
    { label: 'Stack root', value: 'stack' },
    { label: 'BottomTabs root', value: 'bottomTabs' },
    { label: 'SideMenu root', value: 'sideMenu' }
  ]
}>

<TabItem value='stack'>
Stacks are usually used as root for small scale apps or for short-lived flows within one big app. For example, here's a login flow:

```js
Navigation.setRoot({
  root: {
    stack: {
      children: [
        {
          component: {
            name: 'LOGIN_SCREEN'
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='bottomTabs'>
Typically, stacks are used as direct children of BottomTabs and each child is an independent root. This lets users seamlessly switch between tabs as each tab has its own navigation hierarchy.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      children: [
        {
          stack: {
            children: [
              {
                component: {
                  name: 'FEED_SCREEN'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'CHAT_LIST'
                }
              }
            ]
          }
        },
        {
          stack: {
            children: [
              {
                component: {
                  name: 'PROFILE_SCREEN'
                }
              }
            ]
          }
        }
      ]
    }
  }
});
```

</TabItem>

<TabItem value='sideMenu'>
When a SideMenu layout is used as root, the center screen would typically be a stack. The center stack should be treated as a root - you can push child screens into it, or replace it alltogether by calling `setStackRoot`.

```js
Navigation.setRoot({
  root: {
    sideMenu: {
      center: {
        stack: {
          children: [
            {
              component: {
                name: 'HOME_SCREEN'
              }
            }
          ]
        }
      },
      left: {
        component: {
          name: 'MENU_SCREEN'
        }
      }
    }
  }
});
```

</TabItem>
</Tabs>

---

### Website Versioned Docs Version 7.11.2 Docs Docs Screen Lifecycle (`website/versioned_docs/version-7.11.2/docs/docs-screen-lifecycle.mdx`)

---
id: screen-lifecycle
title: Screen Lifecycle
sidebar_label: Screen Lifecycle
---

Any React Component registered with react-native-navigation is enhanced with two additional lifecycle events:

* `componentDidAppear` - called each time a component is revealed to the user
* `componentDidDisappear` - called each time a component is hidden from user's view **as a result of being detached from hierarchy**

These methods compliment React's lifecycle methods:

* `componentDidMount` - called once, when a component is attached to hierarchy **for the first time**
* `componentWillUnmount` - called once, when a component is destroyed

### Mounting
These methods are called in the following order when a component is created and attached to hierarchy.

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

### Unmounting
These methods are called when a component is being removed from hierarchy

* componentDidDisappear()
* componentWillUnmount()

### Modal

When a modal is displayed, depending on the [modalPresentationStyle](/react-native-navigation/api/options-root#modalpresentationstyle), content behind it might be detached from hierarchy. This affects the visibility events which are emitted to the content behind the modal.

When Modals with `pageSheet` or `overCurrentContext` modalPresentationStyle are displayed, previous content is still visible to the user. Thus `componentDidDisappear` event is **not** emitted.

Same is applied when a modal is dismissed. If it was originally presented with `pageSheet` or `overCurrentContext` modalPresentationStyle, when that modal is then dismissed, the previous context won't receive a `componentDidAppear` event.

### Overlay
These methods are called in the following order when a component is displayed as an Overlay:

* constructor()
* render()
* componentDidMount()
* componentDidAppear()

:::note
Content displayed behind an Overlay does not receive the `componentDidDisappear`, since it's still visible to user and attached to the hierarchy.
:::

---

### Website Versioned Docs Version 7.11.2 Docs Docs Showcases (`website/versioned_docs/version-7.11.2/docs/docs-showcases.mdx`)

---
id: showcases
title: Showcases
sidebar_label: Showcases
---

## Apps
### Hekla for Hacker News

A hacker news client built from the ground up with v2 of react-native-navigation. 

It is a tab-based app and utilizes Split Layout for iOS tablets, 3D touch and more.

- [Source code](https://github.com/birkir/hekla)
- [Download iOS](https://itunes.apple.com/us/app/hekla/id1405096983?mt=8)
- [Download Android](https://play.google.com/store/apps/details?id=is.pipe.hekla)

## Starter Kits
* [kanzitelli/expo-rnn-starter](https://github.com/kanzitelli/expo-rnn-starter) - Simple yet practical starter with React Native Navigation and [Expo Modules](https://docs.expo.io/bare/installing-unimodules/), [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) and [Redux](https://github.com/reduxjs/redux) (pick one) and more goodies inside such as Typescript, [RNN Hooks](https://github.com/underscopeio/react-native-navigation-hooks), [RN Vector Icons](https://github.com/oblador/react-native-vector-icons), [RN Gesture Handler](https://github.com/kmagiera/react-native-gesture-handler). As an example, basic Reddit App implemented in two ways: using [MobX-State-Tree](https://github.com/mobxjs/mobx-state-tree) in `/srcMobX` and using [Redux](https://github.com/reduxjs/redux) in `/srcRedux`.
* [atoami/react-native-navigation-redux-starter-kit](https://github.com/atoami/react-native-navigation-redux-starter-kit) - React Native Navigation(v2) Starter Kit with Redux, Saga, ESLint, Babel and Jest 😎
* [alexwasner/react-native-mobx-firebase-starter](https://github.com/alexwasner/react-native-mobx-firebase-starter) - A React Native starter app with React Native Navigation(v2), MobX, Firebase, Lottie and More 🤓

* [hsyndeniz/react-native-quick-start](https://github.com/hsyndeniz/react-native-quick-start) - A React Native starter app with React Native Navigation, Redux, Firebase, Social Auth, Phone Auth, Push Notifications, Google Maps, Google Admob, Lottie and More 🤓

### Playground

The playground example is a place where we showcase and test all features of react-native-navigation.

```bash
git clone https://github.com/wix/react-native-navigation
cd react-native-navigation
npm install

# for iOS:
npm run xcode # Opens XCode
npm start # Starts the packager on linux like systems

# for Android:
# 1. open Android Studio inside ".\playground"
# 2. start a emulator
npm run start-windows # Start the packager if you are on a windows system

# Run the app in Simulator or on Device from within XCode/Android Studio
```

---

### Website Versioned Docs Version 7.11.2 Docs Docs SideMenu (`website/versioned_docs/version-7.11.2/docs/docs-sideMenu.mdx`)

---
id: sideMenu
title: Side Menu
sidebar_label: Side Menu
---

SideMenu provides access to destinations in the app from an easy to access menu which is accessible to the user via horizontal swipe gesture or a menu button.

## Opening programmatically

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu. The menu is opened by setting its visible option to visible.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Opening via the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button at the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

## Pushing to the center layout from a menu
A common use case when using SideMenus is to interact with the center layout, e.g. pushing a screen to a stack in the center layout when a user clicks on a button from one of the menus.

In order to interact with the stack, we'll first assign it a predefined id. For example:

```js
sideMenu: {
  center: {
    stack: {
      id: 'CenterStack',
      children: []
    }
  },
  left: {
    ...
  }
}
```

Now that we've defined an `id` for out stack, we can go ahead and push our screen to it. If we're pushing while the SideMenu is open, we'll need to make sure we close it by updating the visibility option of the relevant menu (left or right).

```js
Navigation.push('CenterStack', {
  component: {
    name: Screens.Pushed,
    options: {
      sideMenu: {
        left: {
          visible: false
        }
      }
    }
  }
});
```

---

### Website Versioned Docs Version 7.11.2 Docs Docs Stack (`website/versioned_docs/version-7.11.2/docs/docs-stack.mdx`)

---
id: stack
title: Stack
sidebar_label: Stack
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

A stack is a container layout promoting a hierarchical navigation. It is used for navigating between screens at consecutive levels of hierarchy, steps in a flow or across an app.

The first child in the stack (represented by the `children` array) is the root and is displayed at the bottom of the stack. The last child in the children array is the child currently being displayed.

In this layout, only a single child screen is visible at any given time and consecutive screen can be added to the top of the stack using the `Navigation.push` command. Tapping the back button will pop the stack and remove the top most screen.

The stack manages the TopBar at the top of the stack. The TopBar displays the current screens' title and buttons. It can be hidden with the `topBar: { visible: false }` option. By default, screens are rendered below the TopBar. This behavior can be changed by setting `topBar: { drawBehind: true }` in the current screens' options.

# Layout Examples

<Tabs
  defaultValue="single"
  values={[
    { label: 'Single child', value: 'single', },
    { label: 'Multiple Children', value: 'multiple', }
  ]
}>
<TabItem value="single">


A stack declared with a single child.

```js
const stack = {
  children: [
    {
      component: {
        name: 'MyComponent',
      },
    },
  ],
};
```

</TabItem>
<TabItem value="multiple">


A stack can be initialized with more than one child, in which case the last child will be the currently displayed child and the first child will be hidden. In this case the back button will be visible automatically, clicking it will go back in the stack revealing the first (previous) child.
Once the root child becomes visible, the back button is hidden.

```js
const stack = {
  children: [
    {
      component: {
        name: 'RootComponent',
      },
    },
    {
      component: {
        name: 'SecondComponent',
      },
    },
  ],
};
```

</TabItem>
</Tabs>


## TopBar Buttons

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

:::tip Always assign titles to buttons!
When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.
:::

### Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](../api/options-button#showasaction) options to control when the button should appear in the menu.

### Using a react component in a button

Sometimes we require more from our buttons. In order to support every product need, React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as their custom view:

```js
topBar: {
  rightButtons: [
    {
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

### Updating props of custom buttons

To update props of a mounted component used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger Reacts component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0
        },
      },,
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

### Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

#### Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

#### Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

## Back Button

The back button is added automatically when two or more screens are pushed into the stack.

### Styling the back button

The back button's style can be customized by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

### Controlling visibility

The back buttons visibility can be controlled with the visible property.

```js
backButton: {
  visible: false;
}
```

### Changing visibility programmatically

Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false,
  },
});
```

### Handling the back button

Handling the back button press event is done by first disabling the default back button behaviour by adding:

```js
topBar: {
  backButton: {
    popStackOnPress: false,
  }
}
```

As a result, pressing the back button will not pop the stack and will dispatch [`navigationButtonPress`](https://wix.github.io/react-native-navigation/api/events#navigationbuttonpressed-event) event with the default back button id `RNN.back`.

### Handling the hardware back button on Android

Same as handling the default back button, handling the hardware back button is done by disabling `popStackOnPress` for the hardware button:

```js
hardwareBackButton: {
  popStackOnPress: false,
}
```

As a result, pressing the hardware back button will not pop the stack and will dispatch [`navigationButtonPress`](https://wix.github.io/react-native-navigation/api/events#navigationbuttonpressed-event) event with the default hardware back button id `RNN.hardwareBackButton`.

## Interacting programmatically

The Navigation object provides ways to programmatically manipulate the stack.

### Interact with the Stack by componentId

Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN',
      },
    });
  };
}
```

### Interact with the Stack by a predefined id

Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent',
          },
        },
      ],
    },
  },
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen',
    },
  });
}
```

---

### Website Versioned Docs Version 7.11.2 Docs Meta Contributing (`website/versioned_docs/version-7.11.2/docs/meta-contributing.mdx`)

---
id: meta-contributing
title: Contributing
sidebar_label: Contributing
---

Thank you for showing interest in contributing to React-Native-Navigation! This project is developed and maintained by Wix in collaboration with the community.

There are various ways in which you can contribute to this library, not all require knowledge or expertise in native development. Listed below is all you need to get started with your first contribution.

## Stack Overflow

Stack Overflow is used by developers to find answers and troubleshoot code. Users are encouraged to post questions on SO and tag them with the [wix-react-native-navigation](https://stackoverflow.com/questions/tagged/wix-react-native-navigation) tag. Answering issues on SO is very helpful and beneficial to the community, only this time, there's a personal angle - you can boost your SO ranking and rack up points quickly.

## Discord

Another popular communication channel is our [Discord channel](https://discord.gg/DhkZjq2) where users post questions and consult with each other. You're welcome to join the discussions and answer questions. This is also a great place to meet other community members and project maintainers.

## Contributing to React-Native-Navigation

### iOS

There are 2 ways to test your contribution to this project on iOS:

1. You can contribute and test your changes using the playground provided.


2. You can install React-Native-Navigation in a new or existing project and set your project to use your local clone of React-Native-Navigation in the podfile.
The following steps are required in order to make the project work with your local environment:

#### 2.1

Install React-Native-Navigation as you'll usually do in your project, using `npm install --save react-native-navigation`.

#### 2.2

Add the following configuration to the `react-native.config.js` file, at the root of your project.

```javascript
module.exports = {
	project: {
		ios: {},
		android: {},
	},
	dependencies: {
		'react-native-navigation': {
			platforms: {
				ios: null,
				android: null
			},
		},
	},
};
```

#### 2.3

Clone the project using `git clone https://github.com/wix/react-native-navigation` at your desired location.

#### 2.4

Add the following line in the Podfile:

```ruby
pod 'ReactNativeNavigation', :path => '/path/to/cloned/react-native-navigation'
```

You're done. Happy coding!

## GitHub Issues

### Open an issue
Found a bug? Missing a feature? Go ahead and open an issue! Make sure to add all details mentioned in the issue template. If you're interested in suggesting a big change, please speak to one of the admins on [Discord](#discord) to coordinate your effort.

### Respond to issues
Although the issue tracker is used solely for bug reports, issues are frequently opened for questions or to request assistance. As the project grows in popularity, more issues remain unanswered for long periods of time.

Some issues can be trivial and easy to pinpoint - a missing import statement or apostrophe, wrong layout structure, etc. If you're an experienced user, helping out newcomers can be quite satisfying and allows maintainers to focus on features and bug fixes.

Some issues are tagged as ["looking for contributors"](https://github.com/wix/react-native-navigation/labels/user%3A%20looking%20for%20contributors). These issues have been recognized by the team, but aren't prioritized by Wix developers due to lack of time or for some other reason. We leave these issues to our community and you're more than welcome to take a crack at them. If you'd like to submit a PR, see [these instructions](#running-the-project) on how to run the project locally.

### Provide reproductions
Reproducing bugs takes time. Lots of time. Usually that's because an issue is lacking important information, which then causes lots of back and forth communication between maintainers and users. Help us address more bugs and issues by providing reproductions.

Providing reproductions improves the chances of an issue being prioritized by maintainers!

If an issue is reproduced with a specific combination of options, posting these options will usually suffice. If a specific layout structure is involved or specific actions need to be performed in a certain order - then we ask that you fork the project and push a branch with a reproduction to the Playground app.

Check out the [list of issues requiring reproductions](https://github.com/wix/react-native-navigation/labels/user%3A%20requires%20reproduction).

## Submitting PRs
So you've fixed a bug or added a feature and you're ready to submit a pull request 🎉🎊 Make sure the title is clear and describes the reason for the PR. Please include any information you can which will help us understand the reasons for the PR, what it fixes and what it changes. Please include before/after pictures/gifs when appropriate.

## Workflow
This project is driven by tests. Before implementing any feature or fixing any bug, a failing test (e2e or unit or both) should be added, depending on the environment of where the fix should be implemented. For example, for an API change, a failing e2e should be written. For a small bug fix in Android, for example, a unit test in Android should be added.

This will ensure good quality throughout the life of the project and will help avoid unexpected breakages.

No PR will be accepted without adequate test coverage.

If you need help running the project, have a look at the [Playground app](playground-app) section. You can run the tests using the scripts below.


### Tests and the Playground app
Besides an overview of basic React Native Navigation functionality, the [Playground app](playground-app) can (and rather should) be used for e2e tests and reproductions. If your change requires an e2e, add it to the playground app, to the appropriate screen. Again, quick setup instructions available in [Playground app](playground-app) section of these docs.

:::tip
If a screen contains too many buttons, e2e tests might fail if the button is positioned out of screen bounds because Detox matchers detect it's invisible.
:::

### Enable linter
The project uses [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) to ensure code style consistency across the codebase. Make sure to install these plugins in your IDE.

A pre-commit hook will verify that the linter passes when committing.

### Playground app Folder Structure

| Folder | Description |
| ------ | ----------- |
| `lib` | The project itself composed of: |
| `lib/android` | android sources and unit tests |
| `lib/ios` | iOS sources and unit tests |
| `lib/src` | TypeScript sources and unit tests |
| `lib/dist` | compiled javascript sources and unit tests |
| `lib/dist/index.js` | the entry point for `import Navigation from 'react-native-navigation'` |
| `e2e` | [detox](https://github.com/wix/detox) e2e tests on both Android and iOS |
| `playground` | The end-user project all e2e tests run against. Contains its own `src`, `android` and `ios`. Does not have its own package.json, depends on the local `<root>/lib` for faster local development (no need to `npm install` locally). |
| `integration` | misc javascript integration tests, proving integration with other libraries like redux |
| `scripts` | all scripts |

### Scripts

| Command | Description |
| ------- | ----------- |
| `npm install` | installs dependencies |
| `npm run build` | compiles TypeScript sources `./lib/src` into javascript `./lib/dist` |
| `npm run clean` | cleans all build directories, stops packager, fixes flakiness by removing watchman cache, etc. |
| `npm run start` | starts the react-native packager for local debugging |
| `npm run xcode` | for convenience, opens xcode in this project |
| `npm run install-android`  |  builds playground debug/release version and installs on running android devices/emulators. <br></br> **Options:** `-- --release` |
| `npm run uninstall-android` | uninstalls playground from running android devices/simulators |
| `npm run test-js` | runs javascript tests and coverage report |
| `npm run test-unit-ios` | runs ios unit tests in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-unit-android` | runs android unit tests in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-e2e-ios` | runs the ios e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release`|
| `npm run test-e2e-android` | runs the android e2e tests using [detox](https://github.com/wix/detox) in debug/release <br></br> **Options:** `-- --release` |
| `npm run test-all` | runs all tests in parallel |

---

### Website Versioned Docs Version 7.11.2 Docs SideMenu Disable (`website/versioned_docs/version-7.11.2/docs/sideMenu-disable.mdx`)

---
id: sideMenu-disable
title: Disable Open and Close gesture
sidebar_label: Open and Close Gesture
---

To open the side menu programmatically, you'll need to update the visible property of the side menu you'd like to open.

The following snippet shows how to open the left side menu.
```jsx
Navigation.mergeOptions(componentId, {
  sideMenu: {
    left: {
      visible: true,
    },
  },
});
```

## Open by pressing on the hamburger menu
The most common use case is to open the side menu by pressing the hamburger button in the TopBar. To achieve this, listen to the press event of the burger button, and open the side menu as shown above.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');
const { View, Text } = require('react-native');

class SideMenuCenterScreen extends React.Component {
  static options() {
    return {
      topBar: {
        leftButtons: {
          id: 'sideMenu',
          icon: require('./menuIcon.png')
        }
      }
    };
  }

  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  render() {
    return (
      <View>
        <Text>Click the hamburger icon to open the side menu</Text>
      </View>
    );
  }

  navigationButtonPressed({ buttonId }) {
    if (buttonId === 'sideMenu') {
      Navigation.mergeOptions(this, {
        sideMenu: {
          left: {
            visible: true
          }
        }
      });
    }
  }
}
```

---

### Website Versioned Docs Version 7.11.2 Docs Stack BackButton (`website/versioned_docs/version-7.11.2/docs/stack-backButton.mdx`)

---
id: stack-backButton
title: The Back button
sidebar_label: Back button
---

The back button is added automatically when two or more screens are pushed into the stack.

## Styling the back button
The back button's style can be customised by declaring a backButton options object. This configuration can be part of a screen's static options, or default options.

```js
backButton: {
  color: 'red',
  icon: require('../../img/customChevron.png')
}
```

## Controling visibility
The back buttons visbility can be controlled with the visible property.

```js
backButton: {
  visible: false
}
```

## Changing visbility programmatically
Back button visibility can be changed dynamically using the mergeOptions command. When using a screen's componentId, the change will affect only that specific screen. But when using the stack's id, the change will affect all screens pushed into the stack.

```js
Navigation.mergeOptions(this.props.componentId, {
  backButton: {
    visible: false
  }
});
```

## Handling the back button
Handling the back button is not possible. However, you can set a left button with a chevron and handle it like you'd handle any other button and calling `Navigation.pop` when desired.

---

### Website Versioned Docs Version 7.11.2 Docs Stack BackNavigation (`website/versioned_docs/version-7.11.2/docs/stack-backNavigation.mdx`)

---
id: stack-backNavigation
title: Back Navigation
sidebar_label: Back navigation
---

## Disabling back navigation

## Handling back navigation

---

### Website Versioned Docs Version 7.11.2 Docs Stack Buttons (`website/versioned_docs/version-7.11.2/docs/stack-buttons.mdx`)

---
id: stack-buttons
title: TopBar Buttons
sidebar_label: TopBar Buttons
---

Buttons can be added to the [right](#rightButtons) and [left](#leftButtons) areas of the TopBar. Buttons can have either an icon or a text. They are declared in the the options object and, as with any other option, can be updated dynamically with the `Navigation.mergeOptions` command.

> When using an icon button on **Android**, you should always pass a title as well. The title is used when the button is collapsed to the overflow menu and as a tooltip when the button is long pressed.

# Overflow menu

It's common practice to group less important actions in a menu or an action sheet.

To do so on iOS, include a button with a menu icon and open an [ActionSheet](https://facebook.github.io/react-native/docs/actionsheetios) with the relevant actions when the button is clicked.

On Android, use the [showAsAction](#showasaction) options to control when the button should appear in the menu.

# Left button

Left buttons behave like right buttons with two caveats on Android:

- Only a single left button is alowed
- Textual left button isn't supported

# Using a react component in a button

> ⚠️At the moment, Android only supports using custom buttons in `rightButtons`.

Sometimes we require more from our buttons. In order to support every product need React Components can be used as custom views of buttons.
To do so, you'll first need to register the view with Navigation, just like you register your components used as screens:

```js
Navigation.registerComponent('ButtonComponent', () => require('./ButtonComponent'));
```

Now you can create buttons which use the component registered with `'ButtonComponent'` as thier custom view:

```js
topBar: {
  rightButtons: [
    {
      component: {
        name: 'ButtonComponent',
        passProps: {
          // Pass initial props to the button here
        },
      },
    },
  ];
}
```

## Updating props of custom buttons

To update props of a mounted compoennt used as a button, you'll first need to assign it a unique id, then call the `Navigation.updateProps()` command with the id.

Calling the updateProps command will trigger React's component lifecycle methods related to [props update](https://reactjs.org/docs/react-component.html#updating)

```js
// Declare the button and assign it a unique id
topBar: {
  rightButtons: [
    {
      id: 'SomeUniqueId',
      component: {
        name: 'ButtonComponent',
        passProps: {
          count: 0
        },
      },,
    },
  ];
}

// Update props
Navigation.updateProps('SomeUniqueId', {
  count: 1,
});
```

# Changing buttons dynamically

As buttons are part of a screen's options, they can be modified like any other styling option using the [mergeOptions](#) command.

## Setting buttons

The following command will set the screen's right buttons. If the screen already has Right Buttons declared - they will be overridden.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [
      {
        id: 'myDynamicButton',
        text: 'My Button',
      },
    ],
  },
});
```

## Removing buttons

Buttons can be removed by setting zero buttons, as shown in the snippet below.

```js
Navigation.mergeOptions(this.props.componentId, {
  topBar: {
    rightButtons: [],
  },
});
```

---

### Website Versioned Docs Version 7.11.2 Docs Stack Programmatically (`website/versioned_docs/version-7.11.2/docs/stack-programmatically.mdx`)

---
id: stack-programmatically
title: Interact programmatically with the Stack
sidebar_label: Interact programmatically
---

The Navigation object provides ways to programmatically manipulate the stack.

## Interact with the Stack by componentId
Each layout pushed into the stack has an id. When in the context of a component, The component's `componentId` can be used to interact with a parent stack.
When using a component's componentId, the native implementation knows to perform the command on the parent Stack of this component.

In this example, we push a screen onto the component's parent stack.

```jsx
const React = require('react');
const Navigation = require('react-native-navigation');

class MyComponent extends React.Component {
  onButtonClick = () => {
    Navigation.push(this.props.componentId, {
      component: {
        name: 'PUSHED_SCREEN'
      }
    });
  }
}
```

## Interact with the Stack by a predefined id
Sometimes we're required to interact with a specific stack not from the context of a component pushed into it. To do so, assign the stack a predefined `id` and use it when invoking any stack command.

```js
Navigation.setRoot({
  root: {
    stack: {
      id: 'MyStack', // This is the id we're going to use when interacting with the stack
      children: [
        {
          component: {
            name: 'SomeComponent'
          }
        }
      ]
    }
  }
});

function push() {
  Navigation.push('MyStack', {
    component: {
      name: 'PushedScreen'
    }
  });
}
```

---

### Website Versioned Docs Version 7.11.2 Docs Style Animations (`website/versioned_docs/version-7.11.2/docs/style-animations.mdx`)

---
id: style-animations
title: Animations
sidebar_label: Animations
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

Various UI elements can be animated by declaring animation options.
You can change the default animations for various commands, like push and pop, and even animate elements in
your screens during screen transitions.

#### Animation properties

The following properties can be animated with our animation framework:

- **x** - Translate the view to a coordinate along the x axis.
- **y** - Translate the view to a coordinate along the y axis.
- **translationX** - Translate the view along the x axis relative to its current x position.
- **translationY** - Translate the view along the y axis relative to its current y position.
- **alpha** - Apply alpha animation to the view. A value of 0 means the view is not visible, 1 means it's visible.
- **scaleX** - Scale the view on the x axis. A value of 1 means that no scaling is applied.
- **scaleY** - Scale the view on the y axis. A value of 1 means that no scaling is applied.
- **rotationX** - Applies rotation around the x axis (in degrees, passed as a float).
- **rotationY** - Applies rotation around the y axis (in degrees, passed as a float).
- **rotation** - Rotates the view on all axis. Positive values result in clockwise rotation.

## Layout animations

### Stack animations

When animating screens in and out of a stack, there are three elements you can work with:

1. **content** - screen being pushed or popped
2. **topBar** - stack's TopBar
3. **bottomTabs** - if stack is a child of a bottomTabs layout, we can control the `hide` and `show` animations of the bottomTabs.

The following example demonstrates how to replace the default push and pop animations with slide animations.

<Tabs
  defaultValue="push"
  values={[
    { label: 'Push', value: 'push', },
    { label: 'Pop', value: 'pop', },
  ]
}>
<TabItem value="push">

```js
options: {
  animations: {
    push: {
      content: {
        translationX: {
          from: require('react-native').Dimensions.get('window').width,
          to: 0,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
<TabItem value="pop">

```js
options: {
  animations: {
    pop: {
      content: {
        translationX: {
          from: 0,
          to: -require('react-native').Dimensions.get('window').width,
          duration: 300
        }
      }
    }
  }
}
```

</TabItem>
</Tabs>

### Modal animations

Modal animations are declared similarly to stack animations, only this time we animate the entire view and not only part of the UI (content).
The appearing modal can play custom enter animation and exit for the disappearing screen when showing/dismissing modal.

<Tabs
  defaultValue="show"
  values={[
    { label: 'Show', value: 'show', },
    { label: 'Dismiss', value: 'dismiss', },
  ]
}>
<TabItem value="show">

The following example demonstrates how to show a modal with a fade-in animation.

:::warning Deprecation warning
```js
options: {
  animations: {
    showModal: {
      alpha: {
        from: 0,
        to: 1,
        duration: 300
      }
    }
  }
}
```
Consider using enter, exit animations instead.
:::
```js
options: {
  animations: {
    showModal: {
    enter :{
      enabled:true,
      alpha: {
            from: 0,
            to: 1,
            duration: 300
       }
    },
    exit :{
      enabled:true,
      alpha: {
                from: 1,
                to: 0,
                duration: 300
           }
        }
    }
  }
}
```


</TabItem>
<TabItem value="dismiss">

The following example demonstrates how to dismiss a modal with a fade-out animation.

:::warning Deprecation warning
Consider using enter, exit animations instead.
```js
options: {
  animations: {
    dismissModal: {
      alpha: {
        from: 1,
        to: 0,
        duration: 300
      }
    }
  }
}
```
:::

```js
options: {
  animations: {
    dismissModal: {
     exit:{
     enabled:true
      alpha: {
             from: 1,
             to: 0,
             duration: 300
         }
      },
      enter:{
       enabled:false
       alpha: {
            from: 0,
            to: 1,
            duration: 300
         }
      }
    }
  }
}
```
</TabItem>
</Tabs>

## Shared element transitions

Shared element transitions allow us to provide visual continuity when navigating between destinations. This also focuses user attention on a particular significant element, which then also gives such user better context when transitioning to some other destination.

:::caution
At the moment, the transition is available for push and pop commands. We are working on expanding supported commands to show/dismiss modal and change BottomTabs.
:::

### Transition breakdown

Let's take a more in-depth look at the following example, which you can find in the playground app:

> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx)

<p align="center">
  <img alt="Shared Element Transition" src={useBaseUrl('img/sharedElement.gif')} />
</p>

Four elements are animated in this example. Let's list the elements involved in the transition and note which properties are being animated.

- **image** - the item image is animated to the next screen.

  - image scale (resizeMode)
  - position on screen

- **image background** - each item has a "shadow" view which transitions to the next screen and turns into a colorful header.

  - scale
  - position on screen
  - color

- **title** - the title of the item is animated to the next screen.

  - font size
  - font color
  - position on screen

- **Description** - the description of the item in the destination screen.
  - fade-in
  - translation y

### Implementing shared element transitions

#### Step 1 - set a nativeID prop to elements in the source screen

In order for RNN to be able to detect the corresponding native views of the elements,
each element must include a unique `nativeID` prop.

```jsx
<Image
  source={item.image}
  nativeID={`image${item.id}`}
  style={styles.image}
  resizeMode={'contain'}
/>
```

#### Step 2 - set a nativeID prop to elements in the destination screen

```jsx
<Image source={this.props.image} nativeID={`image${this.props.id}Dest`} style={styles.image} />
```

#### Step 3 - Declare the shared element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          sharedElementTransitions: [
            {
              fromId: `image${item.id}`,
              toId: `image${item.id}Dest`,
              interpolation: { type: 'linear' }
            },
          ],
        },
      },
    },
  },
});
```

The `interpolation` property is an object which consists of a `type` property, and optional parameters to further configure the interpolation function. The following `type`s are supported:

* `'accelerate'`: Begin building up speed until destination has been reached.
  - `factor`: The acceleration factor. Higher values look faster.
* `'decelerate'`: Start at a high speed and slow down to settle.
  - `factor`: The acceleration factor. Higher values look slower.
* `'accelerateDecelerate'`: Begin building up speed until half of the animation is complete, then begin slowing down to settle.
* `'decelerateAccelerate'`: Start at a high speed and slow down until half of the animation is complete, then speed up again to settle.
* `'linear'`: Linearly move towards the destination.
* `'overshoot'`: Begin building up speed and overshoot the destination, then fling back to settle.
  - `tension`: The tension of the overshoot animation defines how far the object can overshoot. _Default: `1`_
* `'spring'`: Acts like an actual spring. Depending on the configuration, this interpolation can overshoot the destination multiple times, or be very stiff and smoothly ease towards the destination.
  - `mass`: The mass defines how "heavy" the object is. _Default: `3`_
  - `damping`: The damping property specifies how much the moving object is being slowed down. Higher values can lead to overdamping, lower values to underdamping. _Default: `500`_
  - `stiffness`: The stiffness property defines how stiff the animated object is. _Default: `200`_

:::caution
Since a Spring interpolation is not a time based animation, you have to manually tweak the configuration to match the duration of the animation, otherwise the remaining time of the Spring interpolation will get skipped.
:::

## Element Transitions

Element transitions also allow you to animate elements during shared element transitions.

### Recreating

#### Step 1 - Set a nativeID prop to the element you'd like to animate

An element can either be in the source or destination screen.

```jsx
<Text nativeID="description" style={styles.description}>
  {this.props.description}
</Text>
```

#### Step 2 - Declare the element animation when pushing the screen

```jsx
Navigation.push(this.props.componentId, {
  component: {
    name: Screens.CocktailDetailsScreen,
    passProps: { ...item },
    options: {
      animations: {
        push: {
          elementTransitions: [
            {
              id: 'description',
              alpha: {
                from: 0, // We don't declare 'to' value as that is the element's current alpha value, here we're essentially animating from 0 to 1
                duration: SHORT_DURATION,
              },
              translationY: {
                from: 16, // Animate translationY from 16dp to 0dp
                duration: SHORT_DURATION,
              },
            },
          ],
        },
      },
    },
  },
});
```

## Peek and Pop (iOS 11.4+)

react-native-navigation supports [Peek and pop](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/#//apple_ref/doc/uid/TP40016543-CH1-SW3) feature in iOS 11.4 and newer.

This works by passing a ref to a component you want to transform into peek view. We have included a handy component to handle all the touches and ref for you:

```jsx
const handlePress ({ reactTag }) => {
  Navigation.push(this.props.componentId, {
    component {
      name: 'previewed.screen',
      options: {
        preview: {
          reactTag,
          height: 300,
          width: 300,
          commit: true,
          actions: [{
            title: "Displayed Name",
            id: "actionId",
            style: 'default', /* or 'selected', 'destructive'*/
            actions: [/*define a submenu of actions with the same options*/]
          }]
        },
      },
    },
  });
};

const Button = (
  <Navigation.TouchablePreview
    touchableComponent={TouchableHighlight}
    onPress={handlePress}
    onPressIn={handlePress}
  >
    <Text>My button</Text>
  </Navigation.TouchablePreview>
);
```

All options except for reactTag are optional. Actions trigger the same event as [navigation button presses](https://wix.github.io/react-native-navigation/#/docs/topBar-buttons?id=handling-button-press-events). To react when a preview is committed, listen to the [previewCompleted](https://wix.github.io/react-native-navigation/#/docs/events?id=previewcompleted-ios-114-only) event.

---

### Website Versioned Docs Version 7.11.2 Docs Style Constants (`website/versioned_docs/version-7.11.2/docs/style-constants.mdx`)

---
id: style-constants
title: Constants
sidebar_label: Constants
---

React Native Navigation exposes a set of constants which can be used to get the dimensions of various navigation elements on the screen: StatusBar, TopBar and BottomTabs.

## When are constants evaluated
Some of the values exposed through the constants API are actually evaluated only after the UI is created (`setRoot` has been called) and therefore are not accessible through static getters.

For example, if you need to get the height of the BottomTabs, you'll first need to have BottomTabs visible on the screen and only then retrieve their height via the constants API.

:::important
We recommend you don't cache the actual constants object returned by `await Navigation.constants()` as it might not be accurate later on when, for example, a new root is set or orientation changes.
:::

## API
As explained above, constants are evaluated in native each time the API is invoked. That's why `Navigation.constants()` returns a promise and the use is as follows:

```js
const { Navigation } = require('react-native-navigation');
const {
  statusBarHeight,
  topBarHeight,
  bottomTabsHeight
} = await Navigation.constants();
```

---

### Website Versioned Docs Version 7.11.2 Docs Style Fonts (`website/versioned_docs/version-7.11.2/docs/style-fonts.mdx`)

---
id: style-fonts
title: Changing fonts
sidebar_label: Changing fonts
---

Before you begin using your own fonts, you'll first need to add them to the app project.

* **Android** - add the `.ttf` or `.otf` files to `src/main/assets/fonts/`
* **iOS** - follow this [guide](https://medium.com/react-native-training/react-native-custom-fonts-ccc9aacf9e5e)

Once we've added the font files to our project, we can star using them in options.

:::note
When declaring fonts in options, use only the file name without the file type suffix.
:::

## BottomTab font

```js
options: {
  bottomTab: {
    fontFamily: 'helvetica'
  }
}
```

## Button font

```js
options: {
  rightButtons: [
    {
      id: 'SAVE_BUTTON',
      text: 'Save',
      fontFamily: 'helvetica'
    }
  ],
  leftButtons: [
    {
      id: 'CANCEL_BUTTON',
      text: 'Cancel',
      fontFamily: 'helvetica'
    }
  ]
}
```

## Title font

```js
options: {
  topBar: {
    title: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Subtitle font

```js
options: {
  topBar: {
    subtitle: {
      fontFamily: 'helvetica'
    }
  }
}
```

## Back button

In iOS the back button will display the title of the previous screen. Use the `backButton` option to modify its font family.

```js
options: {
  topBar: {
    backButton: {
      fontFamily: 'helvetica'
    }
  }
}
```

---

### Website Versioned Docs Version 7.11.2 Docs Style Orientation (`website/versioned_docs/version-7.11.2/docs/style-orientation.mdx`)

---
id: style-orientation
title: Orientation
sidebar_label: Orientation
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Locking orientation
Orientation can be locked either in the layout level, or across the app via default options. You can declare orientations you'd like your app to support in default options.

<Tabs
  defaultValue="defaultOptions"
  values={[
    { label: 'Locking orientation in default options', value: 'defaultOptions', },
    { label: 'Locking root layout orientation', value: 'root', },
    { label: 'Showing landscape modal', value: 'modal', }
  ]
}>
<TabItem value="defaultOptions">

Setting orientation in default options will affect all screens in all hierarchy levels. It's still possible to override orientation for specific screens.

```js
Navigation.setDefaultOptions({
  layout: {
    orientation: ['portrait']
  }
});
```

</TabItem>
<TabItem value="modal">

The following example demonstrates how to show a modal in landscape orientation.

```js
Navigation.showModal({
  component: {
    name: 'VideoPlayer'
    options: {
      layout: {
        orientation: ['landscape']
      }
    }
  }
});
```

</TabItem>
<TabItem value="root">

Applying orientation in the root level will affect all screens in the root hierarchy level. It **will not** apply to modals.

```js
Navigation.setRoot({
  root: {
    bottomTabs: {
      options: {
        layout: {
          orientation: ['portrait']
        }
      },
      children: [
        ...
      ]
    }
  }
});
```

</TabItem>
</Tabs>

## Changing orientation dynamically

Changing orientation dynamically through `Navigation.mergeOption()` is supported only on Android.

```js
Navigation.mergeOptions(this.props.componentId, {
  layout: {
    orientation: ['landscape']
  }
});
```

---

--- METRICS ---
- Files Extracted: 149
- Estimated Token Budget: ~125273 tokens
- Canonical Reference: https://codewiki.google/github.com/wix/react-native-navigation
