React Navigation 5 Hide Drawer Item

26,180

Solution 1

Solved the issue with the following

import React from 'react';
import { SafeAreaView, View, Text, StyleSheet, Image, Linking } from 'react-native';
import { EvilIcons, AntDesign } from '@expo/vector-icons';
import { useDispatch } from 'react-redux';
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '@react-navigation/drawer';

import MainTabNavigator from './MainTabNavigator';
import FAQStackNavigator from './FAQStackNavigator';
import { TouchableOpacity } from 'react-native-gesture-handler';
import * as authActions from '../store/actions/auth';
import { moderateScale } from '../utils/fontScale';

const MainDrawerNavigator = createDrawerNavigator();

const DrawerNavigator = () => {
    const dispatch = useDispatch();
    return (
    <MainDrawerNavigator.Navigator 
        drawerContent={props => customDrawerContent(props, dispatch)}
        drawerStyle={drawerStyle}
    >
        <MainDrawerNavigator.Screen 
            name="DrawerNav"
            component={MainTabNavigator}
            options={{
                drawerLabel: () => null,
                title: null,
                drawerIcon: () => null
            }}
        />

        <MainDrawerNavigator.Screen
            name="FAQNav"
            component={FAQStackNavigator}
            options={
                { 
                    drawerLabel: "FAQ", 
                    drawerIcon: ({tintColor}) => <EvilIcons name={'question'} size={30} color={tintColor} />
                }
            }
        />
    </MainDrawerNavigator.Navigator>
    )
}

const customDrawerContent = (props, dispatch) => {
    return (
        <View style={{flex: 1}}>
            <View style={{height: '90%'}}>

                <DrawerContentScrollView {...props}>
                        <View style={styles.logoContainer}>
                            <Image 
                                style={styles.image} 
                                fadeDuration={0} 
                                resizeMode={'contain'} 
                                source={require('...')} 
                            />
                        </View>

                        <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('...')}}>
                            <AntDesign style={styles.iconStyle} name={'shoppingcart'} size={25} color={'black'} />

                            <Text style={styles.drawerText}>Shop</Text>                    
                        </TouchableOpacity>

                        <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('...')}}>
                            <AntDesign style={styles.iconStyle} name={'contacts'} size={25} color={'black'} />

                            <Text style={styles.drawerText}>Contact Us</Text>                    
                        </TouchableOpacity>

                        {/* Tried just disabling using DrawerItemList but wasn't working so made
                        complete custom drawer component and navigate properly using props.navigation.navigate */}
                        {/* <DrawerItemList 
                            {...props}
                        /> */}

                        <TouchableOpacity 
                            style={styles.contactUsContainer} 
                            onPress={() => { console.log(props.navigation.navigate('FAQNav'))}}
                        >
                            <EvilIcons name={'question'} size={30} color={'black'} />
                            <Text style={styles.drawerText}>FAQ</Text>                    
                        </TouchableOpacity>
                </DrawerContentScrollView>
            </View>

            <TouchableOpacity 
                style={styles.logoutContainer} 
                onPress={() => { 
                    dispatch(authActions.logout());
                }}>
                    <Text style={styles.logoutText}>SIGN OUT</Text>                    
            </TouchableOpacity>
        </View>
    )
}

const drawerStyle = {
    activeTintColor: 'black',
    inactiveTintColor: 'black',
    labelStyle: {
        fontFamily: 'montserrat',
        marginVertical: 16,
        marginHorizontal: 0,
    },
    iconContainerStyle: {
        justifyContent: 'center',
        alignItems: 'center',
    },
    itemStyle: {

    }
}

const styles = StyleSheet.create({
    safeArea: {
        flex: 1,
        paddingTop: Platform.OS === 'android' ? 25 : 0
    },
    container: {
        flex: 1,  
    },
    logoContainer: {
        width: '100%',
        height: moderateScale(50),
        alignItems: 'center',
        justifyContent: 'center',
        marginBottom: 5,
        padding: 5,
    },
    image: {
        resizeMode: 'contain',
        width: '80%',
        height: '100%',
    },
    contactUsContainer: {
        flexDirection: 'row',
        width: '100%',
        height: 50,
        alignItems: 'center',
        paddingLeft: 15
    },
    logoutContainer: {
        flexDirection: 'row',
        width: '100%',
        height: 50,
        alignItems: 'flex-end',
        justifyContent: 'center',
    },
    drawerText: {
        fontFamily: 'montserrat',
        marginLeft: 16,
    },
    logoutText: {
        fontFamily: 'montserrat',
        color: '#b23b3b'
    }
});

export default DrawerNavigator;

Solution 2

Best solution will be filter the props before pass it to DrawerItemList . This will only work react navigation 5

//custom drawer content
export default props => {
const { state, ...rest } = props;
const newState = { ...state}  //copy from state before applying any filter. do not change original state
newState.routes = newState.routes.filter(item => item.name !== 'Login') //replace "Login' with your route name

return (
     <DrawerContentScrollView {...props}>
         <DrawerItemList state={newState} {...rest} />
    </DrawerContentScrollView>
)

}

Solution 3

Having looked through the React Navigation source code, I think the best option would be to add a drawerItemStyle option to the drawer screen that you want to hide. Just set the height to 0.

E.g.

<Drawer.Screen
  name="Home"
  component={MainStackScreen}
  options={{
    drawerItemStyle: { height: 0 }
  }}
/>

It seems to work perfectly.

I'm using React Navigation 6 but this will probably apply to v5 also.

Solution 4

This works Perfectly

<Drawer.Screen name="Home" component={MainStackScreen}
        options={{
                  drawerItemStyle: { display: 'none' }
        }}
/>

Solution 5

For me you would better creating a nested navigator with stack and drawer screens as documented in https://reactnavigation.org/docs/nesting-navigators/#navigator-specific-methods-are-available-in-the-navigators-nested-inside instead of hiding drawer item.

Share:
26,180

Related videos on Youtube

SKeney
Author by

SKeney

Updated on July 09, 2022

Comments

  • SKeney
    SKeney almost 2 years

    I am trying to hide the ability to press one of my routes in the drawer navigator as it is another navigator and the default location in the app. I want the drawer to simply be used for navigating to extraneous routes that don't fit well into user flow elsewhere. Before React Navigation 5 I was able to achieve this by simply setting drawerLabel: () => null. However now with the changes I cannot figure out how to hide this in the same manner.

    Below is my current navigator code:

    const DrawerNavigator = () => {
        const dispatch = useDispatch();
        return (
        <MainDrawerNavigator.Navigator 
            drawerContent={props => customDrawerContent(props, dispatch)}
            drawerStyle={drawerStyle}
        >
            <MainDrawerNavigator.Screen 
                name="DrawerNav"
                component={MainTabNavigator}
                options={{
                    drawerLabel: () => null,
                    title: null,
                    drawerIcon: () => null
                }}
            />
    
            <MainDrawerNavigator.Screen
                name="FAQNav"
                component={FAQStackNavigator}
                options={
                    { 
                        drawerLabel: "FAQ", 
                        drawerIcon: ({tintColor}) => <EvilIcons name={'question'} size={30} color={tintColor} />
                    }
                }
            />
        </MainDrawerNavigator.Navigator>
        )
    }
    
    const customDrawerContent = (props, dispatch) => {
        console.log(props.descriptors)
        return (
            <View style={{flex: 1}}>
                <View style={{height: '90%'}}>
    
                    <DrawerContentScrollView {...props}>
                            <View style={styles.logoContainer}>
                                <Image 
                                    style={styles.image} 
                                    fadeDuration={0} 
                                    resizeMode={'contain'} 
                                    source={require('../assets/images/spikeball-logo-horizontal.png')} 
                                />
                            </View>
    
                            <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('https://spikeball.com/')}}>
                                <AntDesign style={styles.iconStyle} name={'shoppingcart'} size={25} color={'black'} />
    
                                <Text style={styles.drawerText}>Shop</Text>                    
                            </TouchableOpacity>
    
                            <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('https://support.spikeball.com/')}}>
                                <AntDesign style={styles.iconStyle} name={'contacts'} size={25} color={'black'} />
    
                                <Text style={styles.drawerText}>Contact Us</Text>                    
                            </TouchableOpacity>
    
                            <DrawerItemList 
                                {...props}
                            />
    
                    </DrawerContentScrollView>
                </View>
    
                <TouchableOpacity 
                    style={styles.logoutContainer} 
                    onPress={() => { 
                        dispatch(authActions.logout());
                    }}>
                        <Text style={styles.logoutText}>SIGN OUT</Text>                    
                </TouchableOpacity>
            </View>
        )
    }
    

    Link to image showing the undesired output. Basically I want the blue focus and entire nav item hidden from the naw bar specifically. UNDESIRED Output

  • Matheus
    Matheus almost 4 years
    This is also a not good solution, I've tried this. when doing that all you do is replace a bunch of screens you want to hide in drawer for "one" screen which is the stack navigator, for instance. Maybe you could provide a better example other than linking the docs, which are kida poor. Thanks
  • SKeney
    SKeney almost 4 years
    @Matheus In my application they are not clickable at all. There is no clickable space. If I inspect the actual elements in the drawer they are not viewable or clickable.
  • harshit raghav
    harshit raghav almost 4 years
    The drawer item is hidden but I can still some space at that position. Do you know how that can be removed?
  • SKeney
    SKeney almost 4 years
    @harshitraghav I accomplished it by creating my own drawer content above customDrawerContent. If you notice DrawerItemList is commented out and then I handle navigation myself with my own item components.
  • Matheus
    Matheus almost 4 years
    I have to apologize. I didn't check the part where you draw every item, it really worked. Change some letter in your answer so I can change my vote. Thanks for this answer.
  • SKeney
    SKeney almost 4 years
    @Matheus No worries! Glad it helped!
  • MayankBudhiraja
    MayankBudhiraja over 3 years
    How to hide multiple drawer items?
  • Lenin Sheikh
    Lenin Sheikh over 3 years
    hey @MayankBudhiraja update the Filter like this: newState.routes = newState.routes.filter(item => !['RouteOne', 'Login', 'Signup' ].includes(item.name));
  • targhs
    targhs over 3 years
    Not working in my case. Did exactly the same thing. Asking another question.
  • Gowtham
    Gowtham over 3 years
    This is working. But the first item in the drawer had a blue background. Had to pass activeBackgroundColor={'transparent'} in DrawerItemList. Thanks.
  • ffritz
    ffritz over 3 years
    Working as expected!
  • rafaelmorais
    rafaelmorais over 3 years
    To add to what @Matheus wrote, when I tried this way I was seeing some weird flickering on iOS and when tested it with the drawer as the top navigator its was pretty smooth.
  • Nisharg Shah
    Nisharg Shah over 3 years
    working but sometimes it is not navigate to another screen
  • Raphael Pinel
    Raphael Pinel over 3 years
    Same as @Nisharg Shah, It does not navigate to the 2nd screen on the list.
  • Raphael Pinel
    Raphael Pinel over 3 years
    For it to work, you need to replace <DrawerItemList> with the items you want to have in the list: <DrawerItem label={'yourNavItem'} onPress={() => props.navigation.navigate('yourNavItem')} labelStyle={styles.mainItem} />
  • Admin
    Admin over 3 years
    Someone please help me I have same problem But I do not know what should I modify In code. Check this link = stackoverflow.com/questions/65679208/…
  • Bryson Kruk
    Bryson Kruk over 2 years
    This led me to try using display: "none" instead of height: 0 and it worked perfectly! It also removed the built-in padding/margin
  • Nobady
    Nobady over 2 years
    simple and effective ;-)
  • Md. Sultanul Arefin
    Md. Sultanul Arefin over 2 years
    yes @BrysonKruk answer worked for me, V6 drawerItemStyle: {display: (current_Role===1)?"flex":"none",}
  • nicholascm
    nicholascm over 2 years
    @BrysonKruk I think yours should be the accepted answer :) Very simple and works well.
  • Abid Ali
    Abid Ali about 2 years
    this hides the drawer item but we see an extra space between the items where this hidden item was.
  • Lucas Garcez
    Lucas Garcez about 2 years
    the code works on v6 too!