skip to content

Stack, Tab & Drawer Setup

React Navigation 7 builds screens from NavigationContainer or createStaticNavigation plus native stack, JS stack, bottom tab and drawer navigators. Interviewers ask which stack to pick and why.

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

explore

questions

6

In React Navigation 7, when do you use a stack navigator, bottom tabs or a drawer to organise an app's screens?

level: juniorimportance: must knowfreq 72%

answer

  1. history you push and pop
  2. peer sections that keep their state
  3. a hidden menu of many destinations
  4. tabs go back to the first tab
  5. one NavigationContainer at the root

basics

~20 s

Use a stack for drill-down flows where screens are pushed and popped as history, bottom tabs for a few top-level peer sections that each keep their state, and a drawer when there are more peer destinations than fit in a tab bar.

solid answer

~40 s

A stack (`createNativeStackNavigator` or `createStackNavigator`) models history: each `navigate` or `push` adds a screen on top, back pops it, and the header shows a back button. Bottom tabs (`createBottomTabNavigator`) model peer sections the user switches between; each tab's screen stays mounted after its first visit, so an audiobook app's Home, Search and Library keep their scroll position and search text, and by default `backBehavior: 'firstRoute'` sends back to the first tab. A drawer (`createDrawerNavigator`) also holds peers, but behind a side menu, which suits many or rarely used destinations; it needs `react-native-gesture-handler` and `react-native-reanimated`. Whatever mix you pick, the whole tree lives inside a single `NavigationContainer`, or the component returned by `createStaticNavigation`.

code

tsx · 27 lines
tsx
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStaticNavigation } from '@react-navigation/native';
import { Text } from 'react-native';

function HomeScreen() {
  return <Text>Continue listening</Text>;
}
function SearchScreen() {
  return <Text>Search titles and narrators</Text>;
}
function LibraryScreen() {
  return <Text>Your audiobooks</Text>;
}

const RootTabs = createBottomTabNavigator({
  screens: {
    Home: HomeScreen,
    Search: SearchScreen,
    Library: LibraryScreen,
  },
});

const Navigation = createStaticNavigation(RootTabs);

export default function App() {
  return <Navigation />;
}

go deeper

for a junior

Recall the three patterns: a stack is history you push and pop, tabs are peer sections that keep their state, and a drawer is peers behind a menu, all inside one navigation container.

for a middle

Explain lazy rendering and kept-mounted tabs, the default firstRoute back behaviour, and the extra peer dependencies the drawer brings.

for a senior

Justify the structure of a real app, such as tabs for sections plus a stack for full-screen flows, and anticipate back-button and state-retention behaviour on both platforms.

for a principal

Weigh information architecture: which sections deserve a permanent tab, what moves to a drawer or settings, and how that affects discoverability and deep links.

## Three navigators, three mental models React Navigation 7 ships a navigator per navigation pattern. Each is a package you install next to `@react-navigation/native`, and each decides how screens relate to one another. | Navigator | Package | Screens are | Going back | |---|---|---|---| | Stack | `@react-navigation/native-stack` or `@react-navigation/stack` | A history of pushed screens | Pops the top screen | | Bottom tabs | `@react-navigation/bottom-tabs` | Peers, one visible at a time | Governed by `backBehavior`, default `'firstRoute'` | | Drawer | `@react-navigation/drawer` | Peers behind a side menu | Also a tab-like switch | ## Stack: drill-down and history A stack fits flows where the user goes deeper and comes back: a book list, then a book's details, then a chapter list. Each screen is **pushed** on top of the previous one and **popped** when the user goes back with the header's back button, the iOS swipe gesture or the Android back button. The stack draws a header with the title and back button by default (`headerShown` defaults to `true`). Two stack navigators exist: the **native stack**, built on `react-native-screens` native primitives, and the **JS stack**, implemented in JavaScript with customisable transitions. Choosing between them is a separate decision; React Native's own navigation guide installs `@react-navigation/native-stack` to get started. ## Bottom tabs: peer sections that keep their state An audiobook app has three top-level sections, Home, Search and Library, that the user switches between constantly. They are **peers**, not history. Bottom tabs fit because: - **Each tab is rendered on first visit and then stays mounted.** `lazy` defaults to `true`, so a tab you never open is never rendered, but once visited, its scroll position, typed search query and loaded data survive switching away and back. - **Switching is not a push.** The tab bar shows all sections at once, and pressing a tab selects it rather than stacking it. - **Back behaviour is configurable** through the navigator's `backBehavior`: `'firstRoute'` (the default) returns to the first tab, and other values include `'initialRoute'`, `'order'`, `'history'`, `'fullHistory'` and `'none'`. - **Icons and labels** come from options such as `tabBarIcon({ focused, color, size })` and `tabBarLabel`. Bottom tabs suit a small number of sections, typically those important enough to be visible all the time. ## Drawer: many peers behind a menu `createDrawerNavigator` also switches between peers, but hides them in a side panel opened by a swipe from the edge or a header button. It suits apps with more destinations than a tab bar holds, or with secondary sections (settings, downloads, help) that do not need to be one tap away. Options like `drawerType` (`'front'`, `'back'`, `'slide'` or `'permanent'`; defaulting to `'slide'` on iOS and `'front'` elsewhere) and `drawerPosition` shape it. It lists `react-native-gesture-handler` and `react-native-reanimated` as peer dependencies. ## Putting a navigator on screen Every navigator must sit inside **one** navigation container at the root of the app: 1. **Dynamic API**: render `<NavigationContainer>` and inside it `<Tab.Navigator>` with `<Tab.Screen>` children. 2. **Static API**: define `createBottomTabNavigator({ screens: { Home, Search, Library } })` and render the component returned by `createStaticNavigation(...)`, which wraps a `NavigationContainer` for you. Rendering a second `NavigationContainer` inside the first throws an error telling you that one container at the root is normal; a deliberately separate tree must be wrapped in `NavigationIndependentTree`, and it cannot navigate to the outer screens. ## Choosing, in practice - **Is it history?** Use a stack. - **Are there two to five top-level sections the user hops between?** Use bottom tabs. - **Are there many sections, or rarely used ones?** Use a drawer. - **Real apps combine them**, for example tabs for the sections and a stack on top for the full-screen player. How navigators are nested inside one another is its own topic; this choice is about which navigator models which relationship.

  • The user switches from Search to Library and back. Why is their typed query still there?
    Bottom tab screens stay mounted after their first render, so the Search screen's component state survives while another tab is focused. Only the focused tab is visible; the others are kept, and depending on `detachInactiveScreens` their native views may be detached, but their React state is not lost.
  • What does the Android back button do in a bottom tab navigator with default settings?
    With the default `backBehavior: 'firstRoute'`, going back from any other tab returns to the first tab. From the first tab the tab navigator does not handle it, so the action goes to a parent navigator or, at the root, to the platform's default back handling. Set `backBehavior` to `'history'` or another value to change this.

A stack is a pile of papers on a desk: you add a sheet on top and remove it to get back. Tabs are the drawers of a filing cabinet: each drawer stays exactly as you left it while you open another.

saying these in an interview costs you the question

  • Tabs unmount a screen whenever you switch away from it.
  • Pressing a tab pushes the section onto a history stack like navigate in a stack.
  • A drawer is only a visual alternative to tabs and needs no extra dependencies.
  • Each tab needs its own NavigationContainer.
  • Bottom tabs render every tab on launch by default.
open as a page

In React Navigation 7, how do you choose between the native stack and the JS stack navigator, and what does each trade away?

level: middleimportance: must knowfreq 55%

basics

~20 s

The native stack uses react-native-screens' native navigation primitives, so transitions, header and gestures behave like the platform's own. The JS stack re-implements them in JavaScript, trading that native feel for fully customisable transitions and headers.

open as a page

In React Navigation 7's native stack, how does the presentation option change how an audiobook player screen appears, and what differs on Android?

level: middleimportance: should knowfreq 35%

basics

~20 s

presentation defaults to 'card', a normal push. 'modal' presents the screen modally, 'transparentModal' keeps the previous screen visible behind it, and iOS styles such as 'fullScreenModal' or 'pageSheet' fall back to a plain modal on Android.

open as a page

In React Navigation 7, how do a navigator's screenOptions, a group's screenOptions, a screen's options and navigation.setOptions combine for one screen?

level: middleimportance: should knowfreq 45%

basics

~20 s

They are merged per key in order: the navigator's screenOptions, then each group's screenOptions, then the screen's options, then anything set with navigation.setOptions. Later sources win, and any of them can be a function of { route, navigation, theme }.

open as a page

In React Navigation 7, what is the difference between the static API with createStaticNavigation and the dynamic API inside NavigationContainer?

level: middleimportance: should knowfreq 42%

basics

~20 s

The static API describes navigators as configuration objects and turns the root into a component with createStaticNavigation, which infers types and can generate deep-link paths. The dynamic API renders Navigator and Screen components inside NavigationContainer, trading that automation for runtime flexibility.

open as a page

In an audiobook app using React Navigation 7 bottom tabs, how do lazy, freezeOnBlur, popToTopOnBlur and detachInactiveScreens change how inactive tabs behave?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

lazy (default true) renders a tab on first visit; freezeOnBlur (default false) stops unfocused tabs from re-rendering; popToTopOnBlur (default false) resets a tab's nested stack when leaving it; detachInactiveScreens detaches inactive tabs' native views to save memory.

open as a page