skip to content

Nested Navigators

Tabs inside a stack or a stack inside a tab gives each navigator its own history, header and action handling. Interviewers probe reaching a nested screen and why two headers appear.

part ofReact Nativeoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In React Navigation 7, what changes when a stack is nested inside each tab versus the whole tab navigator being nested inside a stack?

level: juniorimportance: must knowfreq 58%

answer

  1. each navigator keeps its own history
  2. stack in tab keeps the tab bar
  3. root stack screens cover the tabs
  4. real apps combine both
  5. tapping the focused tab pops to top

basics

~20 s

A stack inside a tab gives that tab its own history and keeps the tab bar visible; tabs inside a stack let root-stack screens cover the tab bar. Most apps combine both: per-tab stacks inside a root stack.

solid answer

~50 s

In React Navigation 7 every navigator keeps its own history. Nesting a **stack inside a tab** means screens pushed from the Profile tab, such as Settings, stay inside that tab: the tab bar remains visible and each tab remembers where the user was. Nesting the **tab navigator inside a stack** means screens pushed on the root stack, such as a full-screen Chat or a Paywall modal, cover the tabs entirely. Real apps usually combine both: a root stack holding `MainTabs` plus full-screen flows, and a stack inside each tab for drill-down. The choice decides where each screen belongs: if a screen must hide the tab bar, register it in the root stack rather than toggling the tab bar per screen. A stack inside a tab also pops to its first screen when the user taps the already focused tab.

go deeper

for a junior

Recall that each nested navigator keeps its own history, that stacks inside tabs keep the tab bar, and that root-stack screens cover the tabs.

for a middle

Explain the combined layout, where back goes at each level, the tab navigator's default back behaviour and the pop-to-top on tab press.

for a senior

Show you place screens by whether the tab bar should show, avoid per-screen tab bar toggles and keep the tree shallow enough to link, type and restore.

for a principal

Treat the navigation tree as product architecture: agree which sections get their own history and which flows interrupt them, before features multiply nested navigators.

## Each navigator has its own history In **React Navigation 7**, nesting a navigator means rendering it as the component of a screen in another navigator. The parent treats the whole child navigator as one of its screens, and the child keeps its **own state**: its own routes, its own history and its own header. Where you nest therefore decides which screens share a history and which UI stays on screen. In a dating app with the tabs `Discover`, `Matches` and `Profile`, two layouts are common. ## Stacks inside tabs Each tab renders its own stack, for example the `Profile` tab renders `ProfileHome → Settings → NotificationSettings`. - Pushing `Settings` happens **inside the tab**: the tab bar stays visible below it. - Each tab **remembers its own position**: go from Profile's Settings to Discover and back, and Settings is still there, because the tab and its stack stayed mounted. - Back inside the tab pops that tab's stack; when the stack is at its first screen, back is offered to the tab navigator, which by default returns to the first tab (`backBehavior` defaults to `firstRoute`). - Tapping the **already focused** tab pops its nested stack to the first screen, mirroring platform behaviour; the stack listens for the tab's `tabPress` event, and a listener that calls `preventDefault()` stops it. ## Tabs inside a stack The root is a stack, and one of its screens, say `MainTabs`, renders the tab navigator. - A screen pushed on the **root stack**, such as `Chat` or a `Paywall` modal, is drawn **above** the tab navigator, so the tab bar is hidden for as long as it is open. - Going back from `Chat` reveals the tabs exactly as they were. - Flows that should not show tabs at all, such as onboarding or a photo editor, belong here. ## Comparing the two | Question | Stack inside a tab | Tabs inside a stack | |---|---|---| | Is the tab bar visible on pushed screens? | yes | no, root screens cover it | | Whose history does back walk? | the tab's own stack | the root stack | | Does each tab keep its own position? | yes | not applicable | | Typical screens | drill-down within a section | full-screen flows, modals | ## The combined layout most apps use ```text RootStack ├── MainTabs (bottom tabs) │ ├── Discover (stack) │ ├── Matches (stack) │ └── Profile (stack: ProfileHome, Settings, NotificationSettings) ├── Chat (full screen, no tab bar) └── Paywall (modal) ``` This gives per-tab history for browsing and a root stack for anything that must cover the tabs. The key design rule follows from it: **decide where a screen lives by whether the tab bar should show**. A common anti-pattern is keeping `Chat` inside the Matches stack and hiding the tab bar with a per-screen style toggle; it tends to flicker during transitions and leaves layout gaps, whereas moving `Chat` to the root stack hides the tabs by construction. ## Walking through a session Following one user through the combined layout shows each rule at work: 1. The app opens on `Discover`, the first tab. 2. The user opens `Profile` and pushes `Settings`; the tab bar stays visible because the push happens in the Profile stack. 3. The user switches to `Matches` and opens `Chat`, which lives in the root stack, so the tab bar disappears under it. 4. Going back from `Chat` pops the root stack and reveals `Matches` exactly as it was. 5. Tapping `Profile` shows `Settings` again, because that tab's stack kept its history. 6. Tapping `Profile` a second time pops the Profile stack to `ProfileHome`. **Costs of nesting:** - **Headers double up** when both the parent and the child show one, so decide which navigator owns the header for each screen. - **Navigating across branches** needs the nested form, for example `navigate('Profile', { screen: 'Settings' })`, because actions bubble up to parents but are not passed down into children. - **Deep trees** make linking configuration, typing and state restoration longer, so nest only where a separate history or a different UI is actually needed. - A navigator nested as a screen of the root stack takes part in that stack's transitions, so a pushed root screen animates in over the whole tab UI, tab bar included.

  • The Chat screen should hide the tab bar; why move it to the root stack instead of toggling the tab bar style from inside the Matches stack?
    A screen in the root stack is drawn above the tab navigator, so the tab bar is hidden by structure, with correct transitions and back behaviour. Toggling the tab bar from a nested screen is a per-screen patch that must be undone on every exit path and tends to flicker or leave layout gaps during transitions.
  • What happens when the user taps the Profile tab while already on Profile's Settings screen?
    The nested stack listens for the tab's `tabPress` event; when the tab is already focused and the stack has more than one route, it pops to the first screen, so the user lands on ProfileHome. A `tabPress` listener that calls `preventDefault()` cancels that behaviour.

Stacks inside tabs are like separate notebooks on a desk, each keeping its own page as you switch between them; a root stack is a sheet of paper laid over the whole desk, hiding every notebook until you lift it off.

saying these in an interview costs you the question

  • All tabs share one history, so back from Profile's Settings returns to Discover.
  • Screens pushed inside a tab's stack hide the tab bar by default.
  • Switching tabs resets the nested stack of the tab you leave.
  • Hiding the tab bar per screen is better than moving the screen to a root stack.
  • Nesting navigators makes the child's screens part of the parent's history.
open as a page

With React Navigation 7, how do you open NotificationSettings, a screen in the Profile tab's nested settings stack, from the Discover tab?

level: middleimportance: must knowfreq 60%

basics

~20 s

Navigate to the screen that hosts the nested navigator and name the child in its params: navigate('Profile', { screen: 'NotificationSettings', params, initial: false }). A bare navigate('NotificationSettings') fails in v7 because actions bubble to parents, not into children.

open as a page

In React Navigation 7 nested navigators, how does an action from a nested screen reach a parent navigator, and when do you need navigation.getParent()?

level: middleimportance: should knowfreq 40%

basics

~20 s

An action goes to the screen's own navigator first and bubbles to each parent until one handles it, so navigate('Chat') from a nested screen reaches the root stack. getParent() covers what stays local: the parent screen's options and events.

open as a page

In React Navigation 7, why do two headers appear when navigators are nested, and how does getFocusedRouteNameFromRoute help title the remaining one?

level: middleimportance: should knowfreq 45%

basics

~20 s

The parent and the nested navigator each render a header by default, so two stack up. Hide one level with headerShown: false; if the parent's header stays, getFocusedRouteNameFromRoute(route) in its options reads the focused child's name.

open as a page

In a React Navigation 7 TypeScript app, how do you type a settings screen nested in the Profile tab so it can navigate to root screens?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Declare the child list inside the parent's with NavigatorScreenParams, then type the nested screen with CompositeScreenProps: its own navigator's props first, then the parent's, composed again up to the root. Static configuration infers the nested params automatically.

open as a page