6

How to hide tabbar in specific screen in react-navigation 6 ... Without changing navigation structure as it's the only option available in the docs here

Hend El-Sahli
  • 6,268
  • 2
  • 25
  • 42

7 Answers7

5

Sometimes i used this approach

import { getFocusedRouteNameFromRoute } from ‘@react-navigation/native’;


 export const MainNavigator = () => {
  const getTabBarVisibility = (route) => {
    const routeName = getFocusedRouteNameFromRoute(route);
    const hideOnScreens = [SCREENS.REVIEW_ORDER, SCREENS.ORDER_PAYMENT]; // put here name of screen where you want to hide tabBar
    return hideOnScreens.indexOf(routeName) <= -1;
  };
  return (
    <Tab.Navigator>
      <Tab.Screen
        name={SCREENS.ORDER}
        component={OrderNavigator}
        options={({ route }) => ({
          tabBarVisible: getTabBarVisibility(route),
        })}
      />
      <Tab.Screen name={SCREENS.REWARDS} component={SweetRewardsNavigator} />
      <Tab.Screen name={SCREENS.MY_ACCOUNT} component={MyAccountNavigator} />
    </Tab.Navigator>
  );
};
Slava Vasylenko
  • 838
  • 1
  • 9
  • 14
  • 1
    Would you have any idea how to do this when the tabBar is a custom component? – Aayush Jan 09 '23 at 19:39
  • 1
    Hi @Aayush const focusedOptions = descriptors[state.routes[state.index].key].options; if (focusedOptions.tabBarVisible === false) { return null; } /// TabBar function MyTabBar({ state, descriptors, navigation }) { const focusedOptions = descriptors[state.routes[state.index].key].options; if (focusedOptions.tabBarVisible === false) { return null; } in component that need to hide useEffect(()=>{navigation.setOptions({tabBarVisible:false})},[]) – Slava Vasylenko Jan 09 '23 at 20:42
  • This is what I mean https://stackoverflow.com/a/64098527/8602069 – Slava Vasylenko Jan 09 '23 at 20:47
1

That's how I made it.

I was looking for a way to hide the tabBar in all my screens on ProductsRoutes, except for the Home screen.(the initial route on the ProductsRoutes Navigator)

Here's the ProductsNavigator:

const ProductsRoutes = (): JSX.Element => {
  return (
    <Navigator
      initialRouteName="Home"
      screenOptions={{
        headerShown: false,
      }}
    >
      <Screen name="Home" component={Home} />
      <Screen name="Details" component={Details} />
      <Screen name="Cart" component={Cart} />
      <Screen name="Catalog" component={Catalog} />
      <Screen name="Sales" component={Sales} />
      <Screen name="Favorites" component={Favorites} />
    </Navigator>
  );
};

On my TabRoutes I'm using

import { getFocusedRouteNameFromRoute } from '@react-navigation/native';

to know which screen on ProductsNavigator is the Home screen and which one is not. Based on that condition I can set display:'none' or 'display:'flex' to the tabBarStyle prop on Screen props:

import { getFocusedRouteNameFromRoute } from '@react-navigation/native';

const TabRoutes = (): JSX.Element => {
  return (
    <Navigator
      screenOptions={{
        headerShown: false,
      }}
    >
      <Screen
        name="Store"
        component={ProductsRoutes}
        options={({ route }) => {
          const focusedRouteName = getFocusedRouteNameFromRoute(route);
          if (focusedRouteName === 'Home') {
            return {
              tabBarStyle: { display: 'flex' },
            };
          }

          return {
            tabBarStyle: { display: 'none' },
          };
        }}
      />
    </Navigator>
  );
};

Hope this helps you in some way

Gustavo Ribeiro
  • 393
  • 3
  • 5
1

keyword is call setOptions and set tabBarStyle to {display:'none'}

at first, we set id on the parent navigator like

 <Tab.Navigator
      id="tabs"
      tabBar={props => <FooterTabs {...props} style={{display: 'flex'}} />} //<-- add a style with display:flex means tabbar is visible by default
      >
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Search" component={SearchScreen} />
      <Tab.Screen name="Chat" component={ChatScreen} />
    </Tab.Navigator>

suppose we wanna hide the tabbar in chatscreen

and in chatscreen, key code like this

const ChatScreen = ({navigation}) => {
  useEffect(() => {
    navigation.getParent('tabs').setOptions({tabBarStyle: {display: 'none'}});
    return ()=>{
    //when leave this screen, and the hooks disposed, we set tabBarStyle to {}, means we will use the default style defined above, that is display:'flex'
 
      navigation.getParent('tabs').setOptions({tabBarStyle: {}});
    };
  }, [navigation]);
...

and you may noticed the tabbar in root tab navigator is a custom component, so inside FooterTabs, key code is like this

const FooterTabs = props => {
  const {state, navigation, descriptors, insets, style} = props;
  const focusedRoute = state.routes[state.index];
  const focusedDescriptor = descriptors[focusedRoute.key];
  const focusedOptions = focusedDescriptor.options;

  const {
    tabBarShowLabel,
    tabBarHideOnKeyboard = false,
    tabBarVisibilityAnimationConfig,
    tabBarStyle, //<-- this is get from options,which we set from sub screens 
    tabBarBackground,
    tabBarActiveTintColor,
    tabBarInactiveTintColor,
    tabBarActiveBackgroundColor,
    tabBarInactiveBackgroundColor,
  } = focusedOptions;

  return (
    <HStack
      style={{...props.style, ...tabBarStyle}} //<-- we set the style over here, so when in some specific screen set tabbarstyle to override the display property to 'none', can final make tabbar hidden
      ...

this above code is get from official bottom tabbar component

Kent Wood
  • 1,392
  • 2
  • 14
  • 30
0
var scroll = 0; // at top

const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
    let contentOffsetY = e.nativeEvent.contentOffset.y;
    let diff = contentOffsetY - scroll;
    if (diff < 0) {
      navigation.setOptions({tabBarStyle: {display: 'flex'}});
    } else {
      navigation.setOptions({tabBarStyle: {display: 'none'}});
    }
    scroll = contentOffsetY;
  };

pass this to onScroll of any scrollview component

Lakhwinder Singh
  • 6,799
  • 4
  • 25
  • 42
0

In my case I had a stack navigator screen in which to hide parent and grandparent navigators' tabBars and headers.

export const MyNav = ({
  route,
  navigation
}) => {

   React.useLayoutEffect(() => {
    
        const routeName = getFocusedRouteNameFromRoute(route);


        if (routeName === 'RouteThatNeedsHiddenTabBarsAndHiddenHeader') {
          navigation.setOptions({ tabBarStyle: { display: 'none' } });
          navigation.getParent()?.setOptions({ headerShown: false });
          navigation.getParent()?.getParent()?.setOptions({ tabBarStyle: { display: 'none' } });
        } else {
          navigation.setOptions({
            tabBarStyle: { ...defaultTabBarStyle, display: 'flex' }
          });
          navigation.getParent()?.setOptions({ headerShown: true });
          navigation.getParent()?.getParent()?.setOptions({ tabBarStyle: {display: 'flex' });
        }
      }, [navigation, route]);

      return (
        <Stack.Navigator>
          <Stack.Screen
            name="NormalRoute"
            component={NormalScreen}
          />
          
          <Stack.Screen
            name="RouteThatNeedsHiddenTabBarAndHiddenHeader"
            component={SpecialScreen}              />
        </Stack.Navigator>
      );
  }

A simpler way if only 1 screen needs to be adjusted would be to run the code in target screen as described here:

https://stackoverflow.com/a/70153935/1979861

Florin Dobre
  • 9,872
  • 3
  • 59
  • 93
0

For me getFocusedRouteNameFromRoute returned undefined. So I had to implement some other solution. I created navigation named state in redux in which I added property tabBarHidden. Then in tab navigation screen I did this.

const Tab = createBottomTabNavigator();

const MainNavigator = () => {
  const tabBarHidden = useSelector(state => state.navigation.tabBarHidden); <-- redux selector

  return <Tab.Navigator tabBar={props => (
     <View style={{
         display: tabBarHidden ? 'none' : 'flex'
      }}>
       <BottomTabBar {...props} />       <-- imported from @react-navigation/bottom-tabs
     </View>
  )}>
    // your tabs
  </Tab.Navigator>
}

Then you can use redux actions to update the property For example if you want to hide tab bar in chat component you have to do something like

 useFocusEffect( <-- imported from @react-navigation/native
    useCallback(() => {
     dispatch(hideTabBar()) <-- redux action to set tabBarHidden to true

     return () => {
       dispatch(unhideTabBar())
     }
   }, [dispatch]),
 )
0

I created a simple hook for this, works perfect, just call it on any screen useHideBottomBar(); to hide the bottom bar on that screen. Change the styles to match your design.

import React from 'react';
import {useNavigation} from '@react-navigation/native';
import ThemeContext from '../../contexts/ThemeContext';
import useColours from '../useColours';
import {useTheme} from 'react-native-paper';
import {Platform} from 'react-native';
import {themeFontFamily} from '../../helpers/theme';

export function useHideBottomBar() {
  const navigation = useNavigation();
  const {darkMode} = React.useContext(ThemeContext);
  const colours = useColours();
  const theme = useTheme();

  React.useEffect(() => {
    navigation.getParent()?.setOptions({
      tabBarStyle: {display: 'none'},
      tabBarBadgeStyle: {display: 'none'},
    });
    return () =>
      navigation.getParent()?.setOptions({
        tabBarStyle: {
          backgroundColor: darkMode
            ? theme.colors.surface
            : colours.secondary050,
          borderTopColor: darkMode
            ? theme.colors.surfaceVariant
            : colours.secondary200,
          borderTopWidth: 1,
          height: Platform.OS == 'ios' ? 110 : 80,
          display: 'flex',
        },
        tabBarBadgeStyle: {
          ...themeFontFamily.OpenSansSemiBold,
          backgroundColor: colours.errorDark,
          color: colours.white,
          fontSize: 11,
          padding: 0,
          marginTop: 6,
          display: 'flex',
        },
      });
  }, [navigation]);
}
BennKingy
  • 1,265
  • 1
  • 18
  • 43