Reputation: 1761
I have the following stack navigation and screens:
export const HomeStack = createStackNavigator({
Home: HomeScreen,
Categories: CategoriesScreen,
Products: ProductsScreen,
ProductDetails: ProductDetailsScreen,
})
I want to hide tabs only in ProductDetailsScreen:
export const hideTabBarComponents = [
'ProductDetails',
]
export const MainTabs = createBottomTabNavigator(
{
Home: HomeStack,
Favorite: FavoriteScreen,
Account: AccountScreen,
Help: HelpScreen,
Events: EventsScreen
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
...
},
tabBarLabel: ({ focused, tintColor }) => {
...
},
tabBarVisible: ! hideTabBarComponents.includes(navigation.state.routeName)
}),
}
);
The problem is that can't pass any options to Tab navigation from Stack Navigation
Not all of the stack screens only one of them
Upvotes: 49
Views: 123953
Reputation: 1761
To hide the tab bar in one of the screens, this works for React Navigation v4:
HomeStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
let routeName = navigation.state.routes[navigation.state.index].routeName
if ( routeName == 'ProductDetails' ) {
tabBarVisible = false
}
return {
tabBarVisible,
}
}
For v5, and v6 please check @Chathuranga Kasthuriarachchi's answer here
Upvotes: 67
Reputation: 1261
I achieved that in this way. First the hook:
import {useLayoutEffect} from 'react';
import {useNavigation, useRoute, getFocusedRouteNameFromRoute} from '@react-navigation/native';
export function useHiddenTabs (hiddenTabRoutesArray, fallbackRoute) {
const navigation = useNavigation();
const route = useRoute();
useLayoutEffect(() => {
const routeName = getFocusedRouteNameFromRoute(route) ?? fallbackRoute;
navigation.setOptions({
tabBarVisible: !hiddenTabRoutesArray.includes(routeName),
})
}, [navigation, route]);
}
And then usage:
import {getFocusedRouteNameFromRoute} from '@react-navigation/native';
const routesWithoutTabs = ['ScreenWithoutTabs'];
const StackComponent = ({navigation}) => {
useHiddenTabs(routesWithHiddenTabs, 'FallbackRoute');
return (
<Stack.Navigator /* other props */>
<Stack.Screen
name='ScreenWithoutTabs'
component={ScreenWithoutTabsComponent}
/>
</Stack.Navigator>
);
};
But probbaly you just need to consider to just redesign your routing tree. Maybe these screens just should be somewhere out of your tab navigator.
Upvotes: 2
Reputation: 46
In my case i had a TabBar(Parent) and inside it StackNavigator(Parent 2) and then my DrawerNavigator.
that is the solution that worked for me on react-navigation 6:
import React from 'react';
import { useFocusEffect } from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
const MyStack = ({ navigation, route }) => {
useFocusEffect(
React.useCallback(() => {
const parent = navigation.getParent();
if (route.name === 'myRouteName')
parent.setOptions({ tabBarStyle: { display: 'none' } });
else parent.setOptions({ tabBarStyle: { display: 'flex' } });
return () => {
parent.setOptions({ tabBarStyle: { display: 'flex' } });
};
}, [navigation, route]),
);
return (
<Drawer.Navigator>
<Drawer.Screen name="myRouteName"/>
</Drawer.Navigator>
);
};
Upvotes: 0
Reputation: 1947
For Rect Navigation v6.x, I found 3 different methods to hide the tabBar from some screens. The following script demonstrates each of these methods. Credit goes to the various answers for this question.
// /////////
import { getFocusedRouteNameFromRoute, } from "@react-navigation/native";
const ShiftUpdateEmployerStack = (params) => {
// Method#1: Hides the tabBar on the screen(s), which satisfy a certain condition (or all screens), in a "stack"
React.useLayoutEffect(() => {
// (1.a) Hide the tabBar on all screens in this stack:
// params.navigation.setOptions({ tabBarStyle: {display: "none"} });
// OR (1.b) Hide the tabBar on the screens, which satisfy a certain condition
const routeName = getFocusedRouteNameFromRoute(params.route);
if (routeName === "EmployerMenuScreen") { // the screen, which you want to hide the tabBar on
params.navigation.setOptions({ tabBarStyle: {display: "none"} });
} else {
params.navigation.setOptions({ tabBarStyle: {display: "flex"} });
}
}, [params.navigation, params.route]);
const MyStack = createNativeStackNavigator();
return (
<MyStack.Navigator>
<MyStack.Screen name="SiteListScreen" component={SiteListScreen}/>
</MyStack.Navigator>
);
};
// /////////
const MainNavigator = () => {
const MyNav = createBottomTabNavigator();
return (
<MyNav.Navigator
// (Optional) Using a custom bottom tab bar, instead of the default one. If a custom tab bar is used, additional code is required (below)
tabBar={params => <CustomTabBarContent {...params} />}
// Method#2: Hides the tabBar on some screen(s)
screenOptions={(params) => {
return {
tabBarStyle: { display: (params.route.name === "ListShiftEmployerScreen" ? "none" : "flex") },
};
}}
>
{/* Method#3: Hides the tabBar on all screens in the "stack" */}
<MyNav.Screen name="InitialStack" component={InitialStack} options={{ tabBarLabel: "Home", tabBarStyle: {display: "none"}, }} />
</MyNav.Navigator>
);
};
// ///////// Using a custom tabBar
const CustomTabBarContent = ({ state, descriptors, navigation, }) => {
// If the option (tabBarStyle: { display: "none" }) is used anywhere, the following couple of statements are required
const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions?.tabBarStyle?.display === "none") {
return null;
}
return (
<View style={{ flexDirection: "row" }}>
{state.routes.map((route, index) => {
// more code...
// see https://reactnavigation.org/docs/bottom-tab-navigator
})}
</View>
);
};
Upvotes: 1
Reputation: 32472
Actually, by the docs explanation, it would be better to think deeply and re-arrange the screens to gather Tabbar screens underneath of TabStack and segregate the rest and especially the screens that you don't want to have Tabbar inside them, under the Navigation stack.
But if you want to hide the Tabbar in some sub-screens of a TabStack screen the following codes will be useful:
import { useNavigation } from '@react-navigation/native';
const Account = () => {
const { getParent } = useNavigation();
useEffect(() => {
const parent = getParent();
parent?.setOptions({
tabBarStyle: { display: 'none' },
});
return () => {
parent?.setOptions({
tabBarStyle: { display: 'flex' },
});
};
}, []);
return (
<View>
~~~
And I have created an useful custom hook for it:
import { useEffect } from 'react';
import useNavigation from './useNavigation';
const useHideTabBar = () => {
const { getParent } = useNavigation();
useEffect(() => {
const parent = getParent();
parent?.setOptions({
tabBarStyle: { display: 'none' },
});
return () => {
parent?.setOptions({
tabBarStyle: { display: 'flex' },
});
};
}, []);
};
export default useHideTabBar;
Upvotes: 1
Reputation: 21
<Navigator initialRouteName="Home"}>
<Screen name="Home" component={Home} />
<Screen
name="About"
component={About}
options={{ tabBarStyle: { display: 'none' } }}
/>
</Navigator>
Upvotes: 2
Reputation: 518
export const useHideTabsHook = () => {
const route = useRoute();
const navigation = useNavigation();
const tabHiddenRoutes = getHiddenRoutesForRoute(route.name);
useLayoutEffect(() => {
const routeName = getFocusedRouteNameFromRoute(route);
if (tabHiddenRoutes && tabHiddenRoutes.includes(routeName)) {
navigation.setOptions({ tabBarStyle: { display: 'none' } });
} else {
navigation.setOptions({ tabBarStyle: { display: 'flex' } });
}
}, [navigation, route, tabHiddenRoutes]);
};
write your own logic to get. the routes in each tab getHiddenRoutesForRoute
const getHiddenRoutesForRoute = routeName => {
switch (routeName) {
case 'tab1':
return tab1HiddenRoutes;
case 'tab2':
return tab2HiddenRoutes;
default:
return null;
}
};
Include this hook in each tab stack. this is using React-Navigation v6.
Upvotes: 0
Reputation: 164
REACT Native V6
I am using typescript and I encountered such an issue too. Since the tabBarVisible option is no longer available, I used the tabBarStyle instead and set the display property to 'none'.
Suppose I have two screens, the Home screen which is the tabbed screen and another screen say Side screen which is a Stacked screen where I want to hide the tab bar, then I do this in the Stacked screen navigator component:
const setTabStyleVisibility = (shouldBeVisible: boolean) =>
shouldBeVisible
? ({
tabBarStyle: { display: 'flex' },
} as Partial<BottomTabNavigationOptions>)
: ({
tabBarStyle: { display: 'none' },
} as Partial<BottomTabNavigationOptions>);
I have a custom button defined as:
<Button title={btnTitle} onPress={onPressHandler}/>
On the Home Screen, I have a button which navigates to the Side screen and hides the tab by defining the custom onPressedHandler prop to the custom button as:
onPressHandler={() => {
navigation.setOptions({
...setTabStyleVisibility(false),
});
navigation.navigate("Side");
}}
Then I had a button passed to the next screen (Side screen) where the tab bar will be shown on going back to Home screen. I set the onPressedHandler which is a custom prop to the custom button to
onPressHandler={() => {
navigation.setOptions({
...setTabStyleVisibility(true),
});
navigation.navigate("Home");
}}
Upvotes: 0
Reputation: 144
this worked for me:
<BottomTab.Navigator
screenOptions={{
tabBarStyle: {
display: isTabVisible ? 'flex' : 'none'
}
}}>
where isTabVisible is a global state variable.
Upvotes: -2
Reputation: 998
Easy solution as mentioned in react-navigation library, You can change the navigation structure react-navigation-doc
Upvotes: 0
Reputation: 81
If, like me, you struggled to make this work in React Navigation 6, here is how I achieved it... I had a bottomTabNavigator containing several stacks, and wanted to hide the tabbar on a specific screen (player) of the homestack
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
...
<BottomTabNavigator.Screen
name="HomeStack"
component={HomeStack}
options={({route}) =>({ tabBarStyle: getTabBarStyle(route) })} />
....
const getTabBarStyle = (route) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Home';
let display = (routeName === 'Player') ? 'none':'flex';
return {display}
}
Upvotes: 7
Reputation: 1623
This is how I hide the tab bar in a specific screen in a stack (React Nav 5.x & 6.x)
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
const ProfileStack = createStackNavigator();
const ProfileNavigator = ({ navigation, route }) => {
React.useLayoutEffect(() => {
const routeName = getFocusedRouteNameFromRoute(route);
if (routeName === "Group"){
navigation.setOptions({tabBarVisible: false});
}else {
navigation.setOptions({tabBarVisible: true});
}
}, [navigation, route]);
return(
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} />
<ProfileStack.Screen name="Group" component={GroupScreen} />
</ProfileStack.Navigator>
)};
If you guys have number of screens that need to hide the tabbar use a string array of those route names and hide tabbar if focused route name includes in that array
const tabHiddenRoutes = ["Group","Map"];
if(tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))){
navigation.setOptions({tabBarVisible: false});
}else{
navigation.setOptions({tabBarVisible: true});
}
[Edit] - In case of v6, use display
because tabBarVisible
is deprecated in the favour of tabBarStyle
-
if(tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))){
navigation.setOptions({tabBarStyle: {display: 'none'}});
} else {
navigation.setOptions({tabBarStyle: {display: 'flex'}});
}
Upvotes: 75
Reputation: 583
if you are using navigation 6
: Than The tabBarVisible option is no longer present
.
You can achieve the same behavior by specifying tabBarStyle: { display: 'none' }
in options.
Upvotes: 13
Reputation: 398
The flow goes like this
import {
getFocusedRouteNameFromRoute,
} from "@react-navigation/native";
<BottomTab.Navigator
screenOptions={(props) => {
console.log(getFocusedRouteNameFromRoute(props.route));
return {
tabBarActiveTintColor: Colors.Red,
tabBarInactiveTintColor: Colors.Blue,
headerShown: false,
tabBarStyle: {
display:
getFocusedRouteNameFromRoute(props.route) === "ProdDetails"
? "none"
: "flex",
},
};
}}
>
{...children}
</BottomTab.Navigator>
Cheers
Upvotes: 3
Reputation: 11
import React, {useLayoutEffect} from "react";
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
const MainStackNavigator = ({navigation, route}) => {
useLayoutEffect(() => {
const routeName = getFocusedRouteNameFromRoute(route);
if (routeName === 'Details') {
navigation.setOptions({tabBarVisible: false});
}else {
navigation.setOptions({tabBarVisible: true});
}
}, [navigation, route])
Upvotes: 0
Reputation: 694
You can use the useFocusEffect hook to check if the screen is focused then hide the navigator with navigation.dangerouslyGetParent()
This is a custom hook I created:
import React from 'react';
import { useFocusEffect } from '@react-navigation/native';
const useHideTabBar = (navigation) => {
useFocusEffect(
React.useCallback(() => {
// hide
const parent = navigation.dangerouslyGetParent();
parent.setOptions({
tabBarVisible: false,
});
// reveal after changing screen
return () =>
parent.setOptions({
tabBarVisible: true,
});
}, []),
);
};
export default useHideTabBar;
Upvotes: 1
Reputation: 887
try this code and it's will work:
const getTabBarVisibility = (route) => {
const routName = route.state
? route.state.routes[route.state.index].name
: '';
if (routName == 'chat') {
return false;
} else {
return true;
}
};
Upvotes: 0
Reputation: 84
The are multiple ways to do it in v5: 1. use tabBarVisible option based on specific strings/route names
using the useRoute() hook & setOptions({ tabBarVisible: false })
2. use dangerouslyGetParent() method for dynamic control For specific screen
navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: false })
On scrolling hide the bottom tab bar
const navigation = useNavigation();
const handleScroll = ({ nativeEvent: { contentOffset: { y = 0 }} }) => {
navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: y <= 50 })
}
return (
<ScrollView onScroll={handleScroll} scrollEventThrottle={16}>
...
</ScrollView>
)
3. for simple nesting you can pass the "tab bar navigation" to any stack screen props
// navigation -> is the bottomTab navigation instance
export default ({ navigation }) => {
return (
<Stack.Navigator screenOptions={screenOptions}>
<Stack.Screen name="Trips">
// add a new prop named tabNavigation={navigation}
// you also have access to the stack navigation
{(props) => <Trips tabNavigation={navigation} {...props} />}
</Stack.Screen>
<Stack.Screen name="Trip" component={Trip} />
</Stack.Navigator>
);
}
and use the examples from point 2
tabNavigation?.setOptions({ tabBarVisible: false })
Upvotes: 1
Reputation: 1727
Another way is to use the height of the tab bar to hide it. This is required when using createMaterialTopTabNavigator, since it does not have a tabBarVisible property. You can use a global state variable (Redux or UseState) or you can use something similar to the selected answer, where you keep track of the currently active screen.
Assuming 'hideTab' is a boolean.
const Tab = createMaterialTopTabNavigator();
...
<Tab.Navigator
tabBarOptions={{style: {height: hideTab ? '0%' : null}}>
Upvotes: 1
Reputation: 1
const AppStack = createStackNavigator({
SplashScreen: {
screen: SplashScreen,
navigationOptions: {
header: null,
},
},
Home: Home,
CarouselMap: CarouselMap,
HeatMapComponent: HeatMapComponent,
});
Upvotes: -1
Reputation: 11
You can also create a Modal inside the screen and make it always visible, with something like this:
const Example = () => {
return(
<ScrollView>
<Modal animationType="slide" transparent={true} visible={true} >
<View style={styles.modalExample}>
</View>
</Modal>
</ScrollView>
)
}
And then style it:
const styles = StyleSheet.create({
modalExample: {
height:"100%",
width:"100%",
backgroundColor: "#000000",
},
})
Upvotes: 1
Reputation: 137
const AppNavigation = createBottomTabNavigator( {
Learning:
{
screen: LearningStack,
navigationOptions: {
tabBarLabel: 'Learning',
// tabBarVisible: false,
tabBarIcon: ({ tintColor, focused }) => (
// <Icon name='terminal' size={25} color={Colors.white} />
<Image
source={require('../assets/TabBarIcon/Learning_96px.png')}
style={{ width: 45, height: '90%', }}
/>
),
}
},
Learning
Stack.navigationOptions
= ({ navigation }) => {
let tabBarVisible = false;
let routeName = navigation.state.routes[navigation.state.index].routeName
if (routeName == 'Learning') {
tabBarVisible = true
}
return {
tabBarVisible
}
},
})
Upvotes: 1
Reputation: 527
Another option here would be to add another stack navigator as a parent of the tab navigator, and put the screen that doesn't need the tab navigator there. This is the recommended way in versions of react navigation < 5
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
/* any other route you want to render under the tab bar */
});
const TabNavigator = createBottomTabNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const HomeStack = createStackNavigator({
Tabs: TabNavigator,
Details: DetailsScreen,
/* any other route you want to render above the tab bar */
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: HomeStack,
});
Upvotes: 0
Reputation: 166
This is the solution that I used in my project.
I have a bottom tab navigator, with 2 routes: Home and Profile. The ProfileHomePage route brings to a stack navigation ProfileStackNavigation.
Then, in the ProfileStackNavigation, I have the ProfileHomePage where the bottom tab should appears, and other child pages, where the bottom tabs should not be visible. I added a param tabBarVisible: false
in that pages.
Finally, in the MainTabNavigator ProfileHomePage route, I added the navigationOptions function, to test if the current route has the param tabBarVisible.
const ProfileStackNavigation = createStackNavigator(
{
ProfileHomePage: ProfileHomePage,
AboutAppPage: {screen: AboutAppPage, params: {tabBarVisible: false}},
DiaryPage: {screen: DiaryPage, params: {tabBarVisible: false}},
FilesPage: {screen: FilesPage, params: {tabBarVisible: false}},
NotificationsPage: {screen: NotificationsPage, params: {tabBarVisible: false}},
},
{
initialRouteName: 'ProfileHomePage',
},
);
const MainTabNavigator = createBottomTabNavigator(
{
HomePage: HomePage,
ProfileHomePage: {
screen: ProfileStackNavigation,
navigationOptions: ({ navigation }) => {
const {params = {}} = navigation.state.routes[navigation.state.index];
const tabBarVisible = params.tabBarVisible === false ? params.tabBarVisible : true;
return {
tabBarVisible,
}
}
},
},
{
initialRouteName: 'HomePage',
tabBarComponent: props => <AppFooterTab {...props} />,
},
);
Upvotes: 0
Reputation: 5304
For React Navigation 5, you can do this inside of the stack component:
props.navigation.dangerouslyGetParent().setOptions({
tabBarVisible: false
});
Be careful with using this though, you'll want to reset the tabBarVisible to true once unmounting the component.
For example, with React hooks inside the Stack component:
useEffect(() => {
const parent = props.navigation.dangerouslyGetParent();
parent.setOptions({
tabBarVisible: false
});
return () =>
parent.setOptions({
tabBarVisible: true
});
}, []);
Or you can reset the tabBarVisible in the Stack.Screen component with the back button press like this:
const StackNav = (props) => (
<Stack.Screen
name='name'
component={Name}
options={{
headerTitle: 'Name',
headerLeft: () => (
<Text
onPress={() =>
props.navigation.setOptions({
tabBarVisible: true
})
}
>
on back
</Text>
)
}}
/>
}
(The second approach works better.)
Upvotes: 31
Reputation: 162
first let's creat a stack navigator and call it StackHome
const StackHome = createStackNavigator(
{
Home: Home,
CustomHide: CustomHide,
});
// This code let you hide the bottom app bar when "CustomHide" is rendering
StackHome.navigationOptions = ({ navigation }) => {
let tabBarVisible;
if (navigation.state.routes.length > 1) {
navigation.state.routes.map(route => {
if (route.routeName === "CustomHide") {
tabBarVisible = false;
} else {
tabBarVisible = true;
}
});
}
return {
tabBarVisible
};
};
export default StackHome;
Upvotes: 8
Reputation: 71
With createBottomTabNavigator you can hide it with the defaultNavigationOptions
defaultNavigationOptions: {
tabBarVisible: false,
},
Upvotes: 3
Reputation: 2743
This is how I did. Select the stack in which you want to hide the tab bar. You can select it based on the index.
AppStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible
};
};
Here is the link of the docs of React navigation
Upvotes: 1