React Navigation 3.x – Drawer Navigation in React Native

We are going to implement Drawer Navigation to React Native. In this example, I have used React Navigation 3.x. To understand it more clearly we will start from a simple example.

Table of content

Simple Drawer Navigation

Let’s start from very basic drawer menu. We are going to use HomeScreen, ProfileScreen and SettingsScreen. We have created stateless that only render the our view part.

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createDrawerNavigator, createAppContainer } from 'react-navigation';


const HomeScreen = () => (
  <View style={styles.container}>
      <Text>Home Screen!</Text>
  </View>
);


const ProfileScreen = () => (
  <View style={styles.container}>
      <Text>Profile Screen!</Text>
  </View>
);


const SettingsScreen = () => (
  <View style={styles.container}>
      <Text>Settings Screen!</Text>
  </View>
);


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});


const DrawerNavigator = createDrawerNavigator({
  Home: {
    screen: HomeScreen
  },
  Profile: {
    screen: ProfileScreen
  },
  Settings: {
    screen: SettingsScreen
  }
});

export default App = createAppContainer(DrawerNavigator);

If you run the above code, the default screen is HomeScreen. And if you tap on the screen and drag from left the right then the drawer navigation will be shown. But it is not so attractive and according to UI point of view, a user doesn’t know if there is any drawer navigation exists or not.

Drawer Navigation with Stack Navigator

Time to add Stack Navigator which holds the hamburger menu icon on the left side. Hamburger menu will help to toggle the Drawer Navigation. We have used Ionicons icon which comes pre-packed with Expo CLI. Don’t forget to import the createStackNavigator from React Navigation package.

const DrawerNavigator = createDrawerNavigator({
  Home: {
    screen: HomeScreen
  },
  Profile: {
    screen: ProfileScreen
  },
  Settings: {
    screen: SettingsScreen
  }
});


const StackNavigator = createStackNavigator({
  DrawerNavigator: {
    screen: DrawerNavigator, 
    navigationOptions: ({ navigation }) => {
      const { state } = navigation;

      if(state.isDrawerOpen) {
        return {
          headerLeft: ({titleStyle}) => (
            <TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
              <Ionicons name="ios-close" style={styles.menuClose} size={36} color={titleStyle} />
            </TouchableOpacity>
          )
        }
      }
      else {
        return {
          headerLeft: ({titleStyle}) => (
            <TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
              <Ionicons name="ios-menu" style={styles.menuOpen} size={32} color={titleStyle} />
            </TouchableOpacity>
          )
        }
      }
    }
  }
})

export default App = createAppContainer(StackNavigator);

As you can see at the above codes we have added our Drawer Navigator variable with createStackNavigator and navigationOptions provides some extra functionality to handle the toggle view of the Drawer Navigator. Of cause, we have to show a close icon in place of the Hamburger menu when the Drawer Navigator Open. state.isDrawerOpen will return true when the Drawer Navigator Open.

Add Icons on Drawer Navigator

Drawer Navigator has the options to add Drawer Icons to with the Label name. We have to use navigationOptions property with createDrawerNavigator.

const DrawerNavigator = createDrawerNavigator({
  Home: {
    screen: HomeScreen, 
    navigationOptions: ({ navigation }) => ({
      title: 'Home Screen', 
      drawerLabel: 'Home',
      drawerIcon: () => (
        <Ionicons name="ios-home" size={20} />
      )
    })
  },
  Profile: {
    screen: ProfileScreen, 
    navigationOptions: ({ navigation }) => ({
      title: 'Profile Screen', 
      drawerLabel: 'Profile',
      drawerIcon: () => (
        <Ionicons name="ios-person" size={20} />
      )
    })
  },
  Settings: {
    screen: SettingsScreen, 
    navigationOptions: ({ navigation }) => ({
      drawerIcon: () => (
        <Ionicons name="ios-settings" size={20} />
      )
    })
  }
});

Complete Codes

import React from 'react';
import { Ionicons } from '@expo/vector-icons'
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { createDrawerNavigator, createStackNavigator, createAppContainer } from 'react-navigation';
import { DrawerActions } from 'react-navigation-drawer';


const HomeScreen = () => (
  <View style={styles.container}>
      <Text>Home Screen!</Text>
  </View>
);


const ProfileScreen = () => (
  <View style={styles.container}>
      <Text>Profile Screen!</Text>
  </View>
);


const SettingsScreen = () => (
  <View style={styles.container}>
      <Text>Settings Screen!</Text>
  </View>
);


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  menuOpen: {
    marginLeft: 10, 
    marginTop: 10
  }, 
  menuClose: {
    marginLeft: 14, 
    marginTop: 10
  }
});


const DrawerNavigator = createDrawerNavigator({
  Home: {
    screen: HomeScreen, 
    navigationOptions: ({ navigation }) => ({
      title: 'Home Screen', 
      drawerLabel: 'Home',
      drawerIcon: () => (
        <Ionicons name="ios-home" size={20} />
      )
    })
  },
  Profile: {
    screen: ProfileScreen, 
    navigationOptions: ({ navigation }) => ({
      title: 'Profile Screen', 
      drawerLabel: 'Profile',
      drawerIcon: () => (
        <Ionicons name="ios-person" size={20} />
      )
    })
  },
  Settings: {
    screen: SettingsScreen, 
    navigationOptions: ({ navigation }) => ({
      drawerIcon: () => (
        <Ionicons name="ios-settings" size={20} />
      )
    })
  }
});


const StackNavigator = createStackNavigator({
  DrawerNavigator: {
    screen: DrawerNavigator, 
    navigationOptions: ({ navigation }) => {
      const { state } = navigation;

      if(state.isDrawerOpen) {
        return {
          headerLeft: ({titleStyle}) => (
            <TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
              <Ionicons name="ios-close" style={styles.menuClose} size={36} color={titleStyle} />
            </TouchableOpacity>
          )
        }
      }
      else {
        return {
          headerLeft: ({titleStyle}) => (
            <TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
              <Ionicons name="ios-menu" style={styles.menuOpen} size={32} color={titleStyle} />
            </TouchableOpacity>
          )
        }
      }
    }
  }
})

export default App = createAppContainer(StackNavigator);