React Native course ยท Module 3: Navigation

Drawer Navigation - Palace Side Menu

3 min read ยท
In this lesson7

Drawer Navigation is a slide-out side menu, perfect for applications with many sections or settings.

Installation

npx expo install @react-navigation/drawer
npx expo install react-native-gesture-handler react-native-reanimated

Configuring babel.config.js

// babel.config.js
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['react-native-reanimated/plugin'], // Must be last!
  };
};

Basic Drawer

import { createDrawerNavigator } from '@react-navigation/drawer';
import { Ionicons } from '@expo/vector-icons';

type DrawerParamList = {
  Home: undefined;
  Profile: undefined;
  Settings: undefined;
  Help: undefined;
};

const Drawer = createDrawerNavigator<DrawerParamList>();

function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator
        screenOptions={{
          drawerStyle: {
            backgroundColor: '#0a2e4a',
            width: 280,
          },
          drawerActiveTintColor: '#00d4ff',
          drawerInactiveTintColor: '#a0aec0',
          drawerLabelStyle: {
            marginLeft: -20,
            fontSize: 16,
          },
          headerStyle: {
            backgroundColor: '#0a2e4a',
          },
          headerTintColor: '#fff',
        }}
      >
        <Drawer.Screen
          name="Home"
          component={HomeScreen}
          options={{
            drawerIcon: ({ color, size }) => (
              <Ionicons name="home" size={size} color={color} />
            ),
            drawerLabel: 'Home page',
          }}
        />
        <Drawer.Screen
          name="Profile"
          component={ProfileScreen}
          options={{
            drawerIcon: ({ color, size }) => (
              <Ionicons name="person" size={size} color={color} />
            ),
          }}
        />
        <Drawer.Screen
          name="Settings"
          component={SettingsScreen}
          options={{
            drawerIcon: ({ color, size }) => (
              <Ionicons name="settings" size={size} color={color} />
            ),
          }}
        />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

Custom Drawer Content

import {
  DrawerContentScrollView,
  DrawerItemList,
  DrawerItem
} from '@react-navigation/drawer';

function CustomDrawerContent(props: DrawerContentComponentProps) {
  const { navigation } = props;

  return (
    <DrawerContentScrollView {...props}>
      {/* Header with user profile */}
      <View style={styles.drawerHeader}>
        <Image
          source={{ uri: 'https://example.com/avatar.jpg' }}
          style={styles.avatar}
        />
        <Text style={styles.username}>Poseidon</Text>
        <Text style={styles.email}>poseidon@atlantis.sea</Text>
      </View>

      {/* Separator */}
      <View style={styles.separator} />

      {/* Default screen list */}
      <DrawerItemList {...props} />

      {/* Separator */}
      <View style={styles.separator} />

      {/* Additional items */}
      <DrawerItem
        label="Help"
        icon={({ color, size }) => (
          <Ionicons name="help-circle" size={size} color={color} />
        )}
        onPress={() => {
          // Custom action
          alert('Atlantis Help Center');
        }}
      />

      <DrawerItem
        label="Log out"
        icon={({ color, size }) => (
          <Ionicons name="log-out" size={size} color={color} />
        )}
        onPress={() => {
          // Logout logic
          navigation.closeDrawer();
        }}
      />
    </DrawerContentScrollView>
  );
}

// Usage
<Drawer.Navigator
  drawerContent={(props) => <CustomDrawerContent {...props} />}
>
  {/* Screens */}
</Drawer.Navigator>

Opening/Closing Drawer Programmatically

import { useNavigation, DrawerActions } from '@react-navigation/native';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View>
      <Pressable onPress={() => navigation.dispatch(DrawerActions.openDrawer())}>
        <Text>Open menu</Text>
      </Pressable>

      <Pressable onPress={() => navigation.dispatch(DrawerActions.closeDrawer())}>
        <Text>Close menu</Text>
      </Pressable>

      <Pressable onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}>
        <Text>Toggle menu</Text>
      </Pressable>
    </View>
  );
}

Drawer on the Right Side

<Drawer.Navigator
  screenOptions={{
    drawerPosition: 'right', // Default is 'left'
  }}
>
  {/* Screens */}
</Drawer.Navigator>

Nesting Navigators

function MainStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="MainTabs"
        component={MainTabs}
        options={{ headerShown: false }}
      />
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator>
        <Drawer.Screen
          name="Main"
          component={MainStack}
          options={{ headerShown: false }}
        />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

Drawer Navigation works great in applications with many sections, admin panels, and enterprise applications.

Code for this lesson: App.tsx
import React from 'react';
import { View, Text, Image, StyleSheet } from 'react-native';
import {
  DrawerContentScrollView,
  DrawerItemList,
} from '@react-navigation/drawer';

// Custom Drawer content with a profile header
function CustomDrawerContent(props) {
  return (
    <DrawerContentScrollView {...props}>
      {/* TODO: add a profile header inside <View style={styles.header}>:
          - <Image style={styles.avatar} source={{ uri: 'https://i.pravatar.cc/100' }} />
          - <Text style={styles.name}>Poseidon</Text> */}

      {/* TODO: below the header render the default item list: <DrawerItemList {...props} /> */}

    </DrawerContentScrollView>
  );
}

const styles = StyleSheet.create({
  header: {
    padding: 20,
    alignItems: 'center',
    backgroundColor: '#1a5276',
    marginBottom: 8,
  },
  avatar: {
    width: 72,
    height: 72,
    borderRadius: 36,
    marginBottom: 10,
  },
  name: {
    color: '#fff',
    fontSize: 18,
    fontWeight: '600',
  },
});

export default CustomDrawerContent;

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. Which libraries are required for Drawer Navigator?

  2. 2. How do you set the Drawer on the right side of the screen?

Hands-on tasks in the game

  • Click in order

    Click the elements to open a Drawer programmatically:

  • Code editor

    Complete the CustomDrawerContent code.

Useful articles