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):
npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimatedNote: Output: (Adds the drawer package and its two dependencies. Nothing on screen yet.)
It looks just like the others — you build it with createDrawerNavigator:
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.
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.
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:
- List your main sections. If users switch between equal sections (Home, Search, Profile), reach for tabs.
- If you have many secondary destinations or a menu (Settings, Help, Logout), add a drawer.
- Inside any section that drills deeper (list -> details -> comments), use a stack, nested inside that tab or drawer screen.
- Keep exactly one
NavigationContainerat the very top — nested navigators do not get their own. - If links from outside should open specific screens, add a
linkingconfig (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?
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
- Add a drawer with three entries (Home, Settings, About), each its own screen.
- Nest a stack inside a tab so one tab can drill from a list into a details screen.
🏠 Homework
- 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.