Thiago Nascimento
Thiago Nascimento

Reputation: 1155

React Navigation header title in nested tab navigator

I have a Tab Navigator inside a Stack Navigator and I want the header title to be dynamically configured as the title of the tab selected. Like there's 3 tabs: Home, Profile, Add Item and I want the header title to be "Home" when in the home tab, "Profile" when in the profile tab.

I tried using onStateChange on the root navigator and setOptions on the tab navigator but onStateChange is only available in the and not in the nested navigators.

Is their anyway I can archieve this?

The navigator config is:

const TabNav = (
   <Tab.Navigator>
      <Tab.Screen name='Home' component={HomeScreen}/>
      <Tab.Screen name='Profile' component={ProfileScreen}/>
      <Tab.Screen name='Add Item' component={AddItemScreen}/>
   </Tab.Navigator>
)

<NavigationContainer>
   <Stack.Navigator>
      <Stack.Screen name='Login' component={LoginScreen}/>
      <Stack.Screen name='App' component={TabNav}/>
   </Stack.Navigator>
</NavigationContainer>

Upvotes: 14

Views: 5348

Answers (3)

anthonyg
anthonyg

Reputation: 1

In 2024 with expo and react-navigation v6 it looks like. My navigation was a Stack Navigator nested within a Tab Navigator.

const navigation = useNavigation();
  useFocusEffect(
        useCallback(() => {
            const tabNavigator = navigation.getParent();
            if(tabNavigator){
                tabNavigator.setOptions({
                    title: 'Tab + Header Title'
                    //header only (not tab)
                    //headerTitle: 'Title Here'
                });
            }
        }, [navigation])
    );

Upvotes: 0

wael
wael

Reputation: 386

From documentation https://reactnavigation.org/docs/screen-options-resolution/

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

function getHeaderTitle(route) {
  // If the focused route is not found, we need to assume it's the initial screen
  // This can happen during if there hasn't been any navigation inside the screen
  // In our case, it's "Feed" as that's the first screen inside the navigator
  const routeName = getFocusedRouteNameFromRoute(route) ?? 'Feed';

  switch (routeName) {
    case 'Feed':
      return 'News feed';
    case 'Profile':
      return 'My profile';
    case 'Account':
      return 'My account';
  }
}

<Stack.Screen
  name="Home"
  component={HomeTabs}
  options={({ route }) => ({
    headerTitle: getHeaderTitle(route),
  })}
/>

Upvotes: 5

Mika
Mika

Reputation: 642

I had a similar Navigation hierarchy with react-navigation v5 and I wanted to change the Header Title inside a View in the nested TabNavigator. I finally achieved it by getting the parent navigation item of the StackNavigator with dangerouslyGetParent() and then using setOptions().

So here is your minimal Code for one of the three views inside your TabNav:

import React, {useCallback} from 'react';
import { useNavigation, useFocusEffect } from '@react-navigation/native';

const HomeScreen = (props) => {

    // TabNav navigation item
    const navigation = useNavigation();

    // Effect will be triggered everytime the Tab changes 
    //      Mounting is not enough -> Tabs will not be unmount by change
    useFocusEffect(
        useCallback(() => {

            // Get StackNav navigation item
            const stackNavigator = navigation.dangerouslyGetParent();
            if(stackNavigator){

                // Actually set Title
                stackNavigator.setOptions({
                    title: "Home"
                });
            }
        }, [navigation])
    );
    return (
        /* Component Items */
    );
};

Upvotes: 9

Related Questions