react-native-navigation Documentation

A complete native navigation solution for React Native

13,172 stars MDX 149 files · ~125,362 tokens #hacktoberfest#navigation#navigator#react-native#react-native-navigation
RAW Doc

Technical Documentation: wix/react-native-navigation

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

React Native Navigation

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.

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.

Releases

Repository administrators: see the release runbook for manual releases,
npm trusted publishing setup, and recovery.


Overview (`playground/README.md`)

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 project, bootstrapped using @react-native-community/cli.

Getting Started

Note: Make sure you have completed the 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.

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.

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

  • Android: Press the R key twice or select "Reload" from the Dev Menu, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS).
  • iOS: Press R 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.
  • If you're curious to learn more about React Native, check out the docs.

Troubleshooting

If you're having issues getting the above steps to work, see the Troubleshooting page.

Learn More

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


RELEASING (`docs/RELEASING.md`)

Releasing React Native Navigation

The Release workflow
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.

  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 -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 (`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

Example

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

`updateProps`

Update props of a component registered with registerComponent. Updating props triggers the component lifecycle methods related to 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.
:::


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 IdcomponentId: Optional, the componentId passed to the commandlayout: 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 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 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 on iOS and Android.

registerBottomTabLongPressedListener

Invoked when BottomTab is long pressed by a user. iOS only. Not emitted for custom bottom tab items — 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();

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 Any type of layout. BottomTabs, Stack, SideMenu, Component
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 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 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 Any type of layout. Typically, Component layout is used in Overlays but it's possible to load any other layout (BottomTabs, Stack, SideMenu, Component)
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.

Parameters

Name Required Type Description
layout Yes Layout Any type of layout. BottomTabs, Stack, SideMenu, Component

Example

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

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'
        }
      }
    }
  }
});
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'
            }
          }
        }
      }]
    }
  }
});

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', },
]
}>

The most common use case - push a single React component.
js
Navigation.push(this.props.componentId, {
  component: {
    name: 'example.PushedScreen'
  }
});
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'
        }
      }
    }
  }
});
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'
      }
    }
  }
});

`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 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 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 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 or Layout[] A single Component or array of components.

Example

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

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

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',
    }
  }
]);

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[] YES Child layouts of any kind.

`options`

Type Required Description
Options 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 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 No dynamic options for the layout

`children`

Type Required Description
Layout[] 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 Yes Center component, contains the main application.

`left`

Type Required Description
Layout No Contains the left component layout.
Type Required Description
Layout 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.
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 YES Set master layout (the smaller screen, sidebar)

`detail`

Type Required Description
Layout YES Set detail layout (the larger screen, flexes)

`options`

Type Required Description
Options 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[] YES Child layouts of any kind.

`options`

Type Required Description
Options 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 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

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 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 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 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 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 to style the floating row.

Tab press and selection events match native bottom tabs; long press is not available on custom items. See Custom bottom tabs — 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 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 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. For React tab items, see Custom bottom tabs.

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.

Type Required Platform
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 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 supportAndroid - 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 is used instead.

Type Required Platform
ImageResource 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 as this button's view which will be displayed instead of the regular view.

Type Required Platform
Component No Both

`iconInsets`

IconInsets 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 is specified. For more information, see apple's guidelines.

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 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) 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

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 No iOS

`ImageSystemSource`

`system`

You can use platform specific system icons for iOS only.

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 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.

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

Title text color

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

Title font size

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

Title font

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

TopBar background color

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

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'
    }
  }
}

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
    }
  },
}

Align the React view used as the title

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

Initial props passed to the React component

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

TopBar button color

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

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
}

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'
}

Subtitle color

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

Subtitle font

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

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'
    }
  ]
}

Button font size

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

Left button font size

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

Left button color

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

Left button font weight

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

Right button font size

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

Right button color

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

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'
}

Button font family

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

iOS only

Hide TopBar when list is scrolled

js
topBar: {
  hideOnScroll: true
}

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

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

Remove TopBar border (hair line)

js
topBar: {
  noBorder: true
}

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
}

Title alignment

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

statusBarColor

StatusBar color

js
statusBar: {
  backgroundColor: 'red'
}

NavigationBar color

js
navigationBar: {
  backgroundColor: 'red'
}

drawUnderStatusBar

Draw content behind the StatusBar

js
statusBar: {
  drawBehind: true
}

TopBar height in dp

js
topBar: {
  height: 70
}

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 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:

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.

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 No Both

`bottomTabs`

Controls the bottom tabs container.

Type Required Platform
BottomTabsOptions No Both

`topBar`

Controls the Stack top bar styling.

Type Required Platform
TopBarOptions No

`statusBar`

Controls the system status bar styling.

Type Required Platform
StatusBarOptions No Both

`layout`

Type Required Platform
LayoutOptions No Both

`sideMenu`

Type Required Platform
SideMenuOptions No Both

`overlay`

Type Required Platform
OverlayOptions No Both

`animations`

Type Required Platform
AnimationsOptions No Both
Type Required Platform
ModalOptions No Both

`preview`

Type Required Platform
PreviewOptions No iOS

`splitView`

Type Required Platform
SplitViewOptions No iOS

`fab`

Type Required Platform
Fab 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
  • iOS 12 and below - fullScreen
  • iOS 13 and above - pageSheet
  • 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

    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 No iOS 26+

    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 (PR #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 No Both

    Configure the right side menu.

    Type Required Platform
    SideMenuSide 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

    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 No Both

    `subtitle`

    Controls the top bar subtitle.

    Type Required Platform
    Subitle No Both

    `backButton`

    Controls the top bar back button.

    Type Required Platform
    BackButton No Both

    `background`

    Controls the top bar background.

    Type Required Platform
    Background 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 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.

    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 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 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] 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
    :::

    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 section for more details.

    Type Required Platform
    [Button] No Both

    `rightButtonColor`

    Default color for the right button.

    Type Required Platform
    Color No Both

    Controls the SearchBar.

    Type Required Platform
    OptionsSearchBar No iOS 11+

    :::warning Deprecation warning
    This option is currently deprecated and will be removed in a future release. Please use the OptionsSearchBar 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 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 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 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 as the title. If this option is specified then text is ignored.

    Type Required Platform
    Component 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 :
    A set of React hooks for React Native Navigation.

    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 :
    Drawer API built on top of React Native Navigation for iOS and Android.

    React Native Navigation Search Bar :
    React Native Elements search bar with collapsible header built for React Native Navigation.

    React Native Navigation Bottom Sheet Extension :
    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

    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.

    text
    /* 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.

    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 .

    text
    "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:

    text
    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) 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.

    text
    /* 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.

    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.
    text
    /* 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
    2. 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.

    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:

    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 or dive right into the API here.

    :::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! 👏

    text
    /* Detailed source-code truncated for AI context efficiency. */

    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:

    text
    /* Detailed source-code truncated for AI context efficiency. */

    Lets run our code again - now our design is consistent across both screens.

    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, so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their 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 the library. If you're just looking around, we suggest checking out basic navigation 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 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:

    Selecting Tabs Programmatically

    Tabs can be selected programmatically by updating the currentTabIndex or currentTabId options.

    We'll use the BottomTabs layout showcased above 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 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 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. 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 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 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 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 listeners:

    Listener Custom row
    registerBottomTabPressedListener Yes — every tap (iOS and Android)
    registerBottomTabSelectedListener Yes — when the selected tab changes
    registerBottomTabLongPressedListener No

    bottomTab.selectTabOnPress: when false, pressed still fires; selected does not until you change the tab programmatically (for example via bottomTabs.currentTabIndex).

    bottomTab.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 UITabBarItems 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.


    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:

    text
    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:

    text
    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).

    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}`);
      },
    });

    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 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. 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.

    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

    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.

    Feed a URL into the pipeline as if it had been delivered by the OS.

    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

    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 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), while on Android, 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).

    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' },
    ]}

    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 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 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', }
    ]
    }>

    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.

    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;

    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.

    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;

    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 to receive data when they are created. When displaying the 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, 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() command. Updating props triggers the component lifecycle methods related to 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). 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' }
    ]
    }>

    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'
              }
            }
          ]
        }
      }
    });
    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'
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    });
    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'
            }
          }
        }
      }
    });

    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()

    When a modal is displayed, depending on the 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.

    Starter Kits

    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', }
    ]
    }>

    A stack declared with a single child.

    js
    const stack = {
      children: [
        {
          component: {
            name: 'MyComponent',
          },
        },
      ],
    };

    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',
          },
        },
      ],
    };

    TopBar Buttons

    Buttons can be added to the right and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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 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 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 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". 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 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.

    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 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 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 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 with Prettier 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 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. 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. 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 Options: -- --release
    yarn test-unit-android runs android unit tests in debug/release Options: -- --release
    yarn test-snapshot-ios runs ios snapshot tests Options: -- --release
    yarn test-e2e-ios-ci runs the ios e2e tests using detox in CI mode (release, multi-device)
    yarn test-e2e-android-ci runs the android e2e tests using detox in CI mode (release, multi-device)
    yarn workspace react-native-navigation-playground test-e2e-ios runs the ios e2e tests using detox in debug/release Options: -- --release
    yarn workspace react-native-navigation-playground test-e2e-android runs the android e2e tests using detox in debug/release 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 and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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', },
    ]
    }>

    js
    options: {
      animations: {
        push: {
          content: {
            translationX: {
              from: require('react-native').Dimensions.get('window').width,
              to: 0,
              duration: 300
            }
          }
        }
      }
    }
    js
    options: {
      animations: {
        pop: {
          content: {
            translationX: {
              from: 0,
              to: -require('react-native').Dimensions.get('window').width,
              duration: 300
            }
          }
        }
      }
    }

    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', },
    ]
    }>

    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
               }
            }
        }
      }
    }

    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
             }
          }
        }
      }
    }

    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 and the Destination screen

    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 types 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 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. To react when a preview is committed, listen to the previewCompleted 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 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

    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', }
    ]
    }>

    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'],
      },
    });

    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: [
            ...
          ]
        }
      }
    });

    The following example demonstrates how to show a modal in landscape orientation.

    js
    Navigation.showModal({
      component: {
        name: 'VideoPlayer'
        options: {
          layout: {
            orientation: ['landscape']
          }
        }
      }
    });

    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 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', }
    ]
    }>

    tsx file=./style-screens/static-options-class.tsx
    tsx file=./style-screens/static-options-fn.tsx

    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', }
    ]
    }>

    tsx file=./style-screens/static-options-props-class.tsx
    tsx file=./style-screens/static-options-props-fn.tsx

    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).

    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 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' },
    ]}

    tsx file=./third-party-mobx/counter-store.tsx

    From [email protected] decorators have become an opt-in feature. To enable decorators for mobx, follow the official guide.

    tsx file=./third-party-mobx/counter-store-decorator.tsx

    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.
    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.

    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 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 and optional steps to support 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' },
    ]}

    tsx file=./third-party-typescript/strongly-typed-components-class.tsx
    tsx file=./third-party-typescript/strongly-typed-components-fn.tsx

    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 :
    A set of React hooks for React Native Navigation.

    React Native Navigation Drawer Extension :
    Drawer API built on top of React Native Navigation for iOS and Android.

    React Native Navigation Search Bar :
    React Native Elements search bar with collapsible header built for React Native Navigation.

    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

    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
    text
    /* Detailed source-code truncated for AI context efficiency. */
    1. 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).

    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).

    a. If you're seeing an error message in Xcode such as:

    text
    'ReactNativeNavigation/ReactNativeNavigation.h' file not found.

    You may also need to add a Header Search Path: (screenshots).

    objectivec
    $(SRCROOT)/../node_modules/react-native-navigation/lib/ios
    1. 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
    text
    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.

    text
    /* 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.

    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 .

    text
    "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:

    text
    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) 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.

    text
    /* 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.
    text
    /* 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
    2. 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')} />

    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 or dive right into the API here.

    :::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! 👏

    text
    /* 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:

    text
    /* 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, so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their 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 the library. If you're just looking around, we suggest checking out basic navigation 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 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 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

    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 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), while on Android, 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' },
    ]}

    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

    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 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', }
    ]
    }>

    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>
            
          </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;

    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;

    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 to receive data when they are created. When displaying the 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, 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() command. Updating props triggers the component lifecycle methods related to 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). 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' }
    ]
    }>

    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'
              }
            }
          ]
        }
      }
    });
    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'
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    });
    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'
            }
          }
        }
      }
    });

    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()

    When a modal is displayed, depending on the 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.

    Starter Kits

    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', }
    ]
    }>

    A stack declared with a single child.

    js
    const stack = {
      children: [
        {
          component: {
            name: 'MyComponent',
          },
        },
      ],
    };

    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',
          },
        },
      ],
    };

    TopBar Buttons

    Buttons can be added to the right and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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 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 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 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". 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 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.

    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 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 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 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 with Prettier 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 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.

    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

    Options: -- --release
    npm run test-unit-android runs android unit tests in debug/release

    Options: -- --release
    npm run test-e2e-ios runs the ios e2e tests using detox in debug/release

    Options: -- --release
    npm run test-e2e-android runs the android e2e tests using detox in debug/release

    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 and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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', },
    ]
    }>

    js
    options: {
      animations: {
        push: {
          content: {
            translationX: {
              from: require('react-native').Dimensions.get('window').width,
              to: 0,
              duration: 300
            }
          }
        }
      }
    }
    js
    options: {
      animations: {
        pop: {
          content: {
            translationX: {
              from: 0,
              to: -require('react-native').Dimensions.get('window').width,
              duration: 300
            }
          }
        }
      }
    }

    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', },
    ]
    }>

    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
          }
        }
      }
    }

    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
          }
        }
      }
    }

    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 and the Destination screen

    Shared Element Transition

    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

    Step 2 - set a nativeID prop to elements in the destination screen

    jsx

    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 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. To react when a preview is committed, listen to the previewCompleted 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

    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', }
    ]
    }>

    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']
      }
    });

    The following example demonstrates how to show a modal in landscape orientation.

    js
    Navigation.showModal({
      component: {
        name: 'VideoPlayer'
        options: {
          layout: {
            orientation: ['landscape']
          }
        }
      }
    });

    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: [
            ...
          ]
        }
      }
    });

    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 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', }
    ]
    }>

    tsx file=./style-screens/static-options-class.tsx
    tsx file=./style-screens/static-options-fn.tsx

    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', }
    ]
    }>

    tsx file=./style-screens/static-options-props-class.tsx
    tsx file=./style-screens/static-options-props-fn.tsx

    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).

    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 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.
    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.

    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 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' },
    ]}

    tsx file=./third-party-typescript/strongly-typed-components-class.tsx
    tsx file=./third-party-typescript/strongly-typed-components-fn.tsx

    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 :
    A set of React hooks for React Native Navigation.

    React Native Navigation Drawer Extension :
    Drawer API built on top of React Native Navigation for iOS and Android.

    React Native Navigation Search Bar :
    React Native Elements search bar with collapsible header built for React Native Navigation.

    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

    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
    text
    /* Detailed source-code truncated for AI context efficiency. */
    1. 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).

    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).

    a. If you're seeing an error message in Xcode such as:

    text
    'ReactNativeNavigation/ReactNativeNavigation.h' file not found.

    You may also need to add a Header Search Path: (screenshots).

    objectivec
    $(SRCROOT)/../node_modules/react-native-navigation/lib/ios
    1. 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> *)extraModulesForBridge:(RCTBridge *)bridge {
      return [ReactNativeNavigation extraModulesForBridge:bridge];
    }
    
    @end
    text
    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.

    text
    /* 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.

    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 .

    text
    "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:

    text
    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) 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.

    text
    /* 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.
    text
    /* 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
    2. 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')} />

    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 or dive right into the API here.

    :::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! 👏

    text
    /* 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:

    text
    /* 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, so some experience with it and knowledge of core concepts is required. If you feel the need, you can start with their 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 the library. If you're just looking around, we suggest checking out basic navigation 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 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 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

    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 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), while on Android, 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' },
    ]}

    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 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 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', }
    ]
    }>

    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>
            
          </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;

    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;

    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 to receive data when they are created. When displaying the 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, 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() command. Updating props triggers the component lifecycle methods related to 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). 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' }
    ]
    }>

    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'
              }
            }
          ]
        }
      }
    });
    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'
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    });
    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'
            }
          }
        }
      }
    });

    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()

    When a modal is displayed, depending on the 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.

    Starter Kits

    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', }
    ]
    }>

    A stack declared with a single child.

    js
    const stack = {
      children: [
        {
          component: {
            name: 'MyComponent',
          },
        },
      ],
    };

    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',
          },
        },
      ],
    };

    TopBar Buttons

    Buttons can be added to the right and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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 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 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 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 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 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". 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 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.

    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 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 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 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 with Prettier 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 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.

    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

    Options: -- --release
    npm run test-unit-android runs android unit tests in debug/release

    Options: -- --release
    npm run test-e2e-ios runs the ios e2e tests using detox in debug/release

    Options: -- --release
    npm run test-e2e-android runs the android e2e tests using detox in debug/release

    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 and left 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 with the relevant actions when the button is clicked.

    On Android, use the 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

    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', },
    ]
    }>

    js
    options: {
      animations: {
        push: {
          content: {
            translationX: {
              from: require('react-native').Dimensions.get('window').width,
              to: 0,
              duration: 300
            }
          }
        }
      }
    }
    js
    options: {
      animations: {
        pop: {
          content: {
            translationX: {
              from: 0,
              to: -require('react-native').Dimensions.get('window').width,
              duration: 300
            }
          }
        }
      }
    }

    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', },
    ]
    }>

    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
               }
            }
        }
      }
    }

    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
             }
          }
        }
      }
    }

    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 and the Destination screen

    Shared Element Transition

    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

    Step 2 - set a nativeID prop to elements in the destination screen

    jsx

    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 types 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 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. To react when a preview is committed, listen to the previewCompleted 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

    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',