Going Pro: Job-Ready React NativeExtra· 40 min read

Drawer & Nested Navigation, Deep Linking

Beyond stack and tabs, real apps use a slide-in drawer, navigators nested inside each other, and deep links that open a specific screen from a URL.

What you will learn

  • Add a slide-in drawer navigator
  • Nest a stack inside a tab for drill-down sections
  • Open a specific screen from a link with deep linking

A third kind of navigator

You know two navigators: a stack (drill in, back button) and tabs (switch top-level sections). The third common one is a drawer: a panel that slides in from the side, usually opened by a hamburger (≡) icon, holding links like Home, Settings and Logout. Gmail and many apps use one.

Install it (one-time):

Install the drawer navigator (it needs gesture-handler and reanimated)
npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimated

Note: Output: (Adds the drawer package and its two dependencies. Nothing on screen yet.)

It looks just like the others — you build it with createDrawerNavigator:

A drawer navigator with two side-menu entries
import { createDrawerNavigator } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';

const Drawer = createDrawerNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator>
        <Drawer.Screen name="Home" component={HomeScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

Note: Output: A hamburger (≡) icon appears at the top left. Tap it (or swipe from the left edge) and a side panel slides in listing "Home" and "Settings". Tap one to switch screens; the panel slides away.

Nesting navigators

Nesting means putting one navigator inside a screen of another. This is how real apps combine patterns: a tab bar at the bottom, where the "Home" tab is itself a stack so it can drill from a list into details — while the tabs stay put. The rule from the tabs lesson still holds: only one NavigationContainer at the very top.

A stack nested inside a tab — drill down while the tab bar stays
const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();

// the Home tab is a stack: List -> Details
function HomeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="List" component={ListScreen} />
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="HomeTab" component={HomeStack} options={{ title: 'Home' }} />
        <Tab.Screen name="Profile" component={ProfileScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Note: Output: A bottom tab bar with "Home" and "Profile". On the Home tab you see a list; tapping an item pushes a Details screen (with a back arrow) while the tab bar stays visible at the bottom. Profile is a separate, flat tab.

Deep linking — open a screen from a URL

Deep linking lets a link from outside the app (an email, a notification, the web) open a specific screen, not just the home screen. You describe a map from URL paths to screen names in a linking config and pass it to the container.

A linking config maps URL paths to screens (and reads params)
const linking = {
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Details: 'item/:itemId',   // myapp://item/42 -> Details with itemId 42
    },
  },
};

<NavigationContainer linking={linking}>
  {/* navigators here */}
</NavigationContainer>

Note: Output: Opening the link myapp://item/42 (e.g. from a push notification) launches the app straight onto the Details screen with route.params.itemId equal to "42" — skipping Home entirely. The :itemId part captures whatever is in that slot of the URL.

Choosing a navigator, step by step

When you plan an app’s navigation, decide in this order:

  1. List your main sections. If users switch between equal sections (Home, Search, Profile), reach for tabs.
  2. If you have many secondary destinations or a menu (Settings, Help, Logout), add a drawer.
  3. Inside any section that drills deeper (list -> details -> comments), use a stack, nested inside that tab or drawer screen.
  4. Keep exactly one NavigationContainer at the very top — nested navigators do not get their own.
  5. If links from outside should open specific screens, add a linking config (deep linking) on that single container.

Tip: With TypeScript (from the earlier lesson), give each nested navigator its own ParamList type so navigate and route.params stay checked even across nested levels.

Watch out: A classic nesting bug is adding a second NavigationContainer around a nested navigator. There must be only one, at the root — the inner navigators are used bare, exactly like HomeStack above.

Q. What does deep linking let a URL like myapp://item/42 do?

Answer: A linking config maps URL paths to screen names (and params), so an outside link can launch the app directly onto a specific screen — here Details with itemId 42.

✍️ Practice

  1. Add a drawer with three entries (Home, Settings, About), each its own screen.
  2. Nest a stack inside a tab so one tab can drill from a list into a details screen.

🏠 Homework

  1. Sketch the navigation for a shopping app: tabs (Home, Cart, Profile), a stack inside Home for product details, and a deep link that opens a product by id.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →