How to add a Drawer Inside Stack Navigation in React Navigation

For those looking for the solution in react-navigation 5.X, you can do it like this:

Drawer Navigator

const ProductListWithDrawer = () => {
 return (
  <Drawer.Navigator initialRouteName="ProductList">
   <Drawer.Screen name="ProductList" component={screens.ProductList} />
   <Drawer.Screen name="ProductDetail" component={screens.ProductDetailScreen} />
  </Drawer.Navigator>
  );
 };

Stack Navigator (should be wrapped inside a Navigation Container)

<Stack.Navigator initialRouteName="Dashboard" screenOptions={{ headerShown: false }}>
  <Stack.Screen name="Dashboard" component={screens.Dashboard} />
  <Stack.Screen name="Loading" component={screens.Loading} />
  <Stack.Screen name="Chat" component={screens.Chat} />
  <Stack.Screen name="ProductListWithDrawer" component={ProductListWithDrawer} /> //our drawer
</Stack.Navigator>

Basically, this should get the work done. One more thing that could be the issue here is while navigating to those screens inside drawer navigator with params. In that case, it can be done like this:

navigation.navigate("ProductListWithDrawer", {
              screen: "ProductList",
              params: { user: "Alex"},
            });

This has also been explained in Nesting navigators.


I have just created an example that probably cases you need.

import React, {Component} from 'react';
import {
  StyleSheet,
  Button,
  Image,
  TouchableWithoutFeedback,
  View,
} from 'react-native';
import {
  createDrawerNavigator,
  createStackNavigator,
  StackActions,
  NavigationActions,
} from 'react-navigation';


class HomeScreen extends React.Component {
  render() {
    return (
        <View style={styles.container}>
          <Button
              onPress={() => this.props.navigation.navigate('Notifications')}
              title="Go to notifications"
          />
        </View>
    );
  }
}

class NotificationsScreen extends React.Component {
  render() {
    return (
        <View style={styles.container}>
          <Button
              onPress={() => this.props.navigation.navigate('Home')}
              title="Go back home"
          />
        </View>
    );
  }
}

class LoginScreen extends Component {
  openDashboard = () => {
    const resetAction = StackActions.reset({
      index: 0,
      actions: [NavigationActions.navigate({routeName: 'Dashboard'})],
    });
    this.props.navigation.dispatch(resetAction);
  }

  render() {
    return (
        <View style={styles.container}>
          <Button
              onPress={this.openDashboard}
              title={'Login'}
          />
        </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 20,
  },
  icon: {
    width: 24,
    height: 24,
  },
  menu: {
    marginRight: 8,
  }
});

const renderMenu = (navigation) => (
    <TouchableWithoutFeedback onPress={() => navigation.openDrawer()}>
      <Image
          source={require('./menu.png')}
          style={[styles.icon, styles.menu]}
      />
    </TouchableWithoutFeedback>
)

const Home = createStackNavigator({
  Home: {
    screen: HomeScreen,
    navigationOptions: ({navigation}) => ({
      title: 'Home',
      headerRight: renderMenu(navigation)
    }),
  }
})

const Notifications = createStackNavigator({
  Notifications: {
    screen: NotificationsScreen,
    navigationOptions: ({navigation}) => ({
      title: 'Notifications',
      headerRight: renderMenu(navigation)
    })
  }
})

const Dashboard = createDrawerNavigator(
    {
      Home: {
        screen: Home,
        navigationOptions: {
          drawerLabel: 'Home',
          drawerIcon: (
              <Image
                  source={require('./chats-icon.png')}
                  style={styles.icon}
              />
          ),
        }
      },
      Notifications: {
        screen: Notifications,
        navigationOptions: {
          drawerLabel: 'Notifications',
          drawerIcon: (
              <Image
                  source={require('./notif-icon.png')}
                  style={styles.icon}
              />
          ),
        }
      },
    },
    {
      drawerPosition: 'right'
    }
);

const App = createStackNavigator(
    {
      Login: LoginScreen,
      Dashboard: Dashboard
    },
    {
      initialRouteName: 'Login',
      headerMode: 'none'
    }
)

export default App;
  • When user presses login button on LoginScreen the navigation will be reseted (so that the user can't goes back to the login screen via the back arrow or the physical back button on android).
  • Then we create a Drawer to the right with two screens and with a hamburger icon.
  • The sub screens for the Home should be inside the Home stack and the same for the notifications.

You just need to add the missing icons.


Showing drawer from right side.

Add a drawer Position parameter when create Drawer Navigator.

const DrawerNav = createDrawerNavigator({
  DashboardStack: Dashboard, 
},
{
  drawerPosition: 'right'
});

Call DrawerNavigation from header's button.

Add a button to the header for toggleDrawer in Dashboard.js. You can get the navigation instance as below in navigationOptions;

class Dashboard extends React.Component {
  static navigationOptions = ({navigation, navigationOptions}) => {
    return {
      headerTitle: 'Dashboard@@',
      headerLeft: <Text>Left</Text>,
      headerRight: (
        <Button onPress = {navigation.toggleDrawer}
        title="Menu"
        color="#fff">
          <Text>Menu</Text>
        </Button>
      ),
      headerTitleStyle: {
        flex: 1,
        color: '#fff',
        textAlign: 'center',
        alignSelf: 'center',
        fontWeight: 'normal',
      },

      headerStyle: {
        backgroundColor: '#b5259e',
      },
    }
  }

You could change button to Touchable Opacity or another one.

Wrap AuthStackNavigation and DrawerNavigation using another Navigator.

Wrap your navigation using createSwitchNavigation or another and export.

// App.js

import React from 'react';

import {
  createStackNavigator,
  createDrawerNavigator,
  createSwitchNavigator,
} from 'react-navigation';

import HomeScreen from './srcs/screens/Home';
import Dashboard from './srcs/screens/Dashboard';

const AuthStackNavigation = createStackNavigator({
  HomeStack: HomeScreen,
  LoginStack: HomeScreen,
  RegisterStack: HomeScreen,
}, {
  initialRouteName: 'HomeStack',
})

const DashboardStack = createStackNavigator({ // For header options
  Dashboard: Dashboard
})

const DrawerNav = createDrawerNavigator({
  DashboardStack: DashboardStack,
  SecondScreen: Dashboard, // You should use another screen.
  ThirdScreen: Dashboard,
})

const MainNavigation = createSwitchNavigator({
  HomeDrawer: DrawerNav,
  AuthStack: AuthStackNavigation, // You will use this.props.navigation.replace('HomeDrawer') after login process.
})

export default MainNavigation // Stack, Drawer, Switch naviagtions return react component.