Keep header with nested createBottomNavigator

Every once in a while you into these strange annoying issues when working with React Native. For a lot of things it is really good and you really feel and are productive. But then these little annoyances just sneak up on you out of the blue.

This issue with createBottomNavigator and the header was one of these for me. I have spent waaay to long on this issue. Tried to solve it many times but then just ended up throwing in the towel time and time again. I have searched all over the Internet and only found people with somewhat the same issue – but never someone who actually had a solution for it. But today I finally managed to solve it and thought I might as well spent the time waiting for the build to iOS to finish, with writing up this little piece on my findings.

The issue:

I have a stackNavigator that has all my screen defined and acts as my “main” navigator. But I wanted to have my first screen be presented with a bottom tab navigator. Implementing this was not that hard as I just created a “createBottomTabNavigator” with the two screen I wanted to show and then defined small icons and texts for these small tabs. This worked out of the box. But what did not work was that I suddenly had my header-bar in the top of the screen not showing any text. Usually this is controlled via the “title” property, but this was totally ignored and I had no text at all in the header.

I tried setting the title all sorts of places in my “createBottomNavigator”, but nothing seemed to work. I tried changing the formatting if the text for some reason was written with the same color as the background. But still to no avail.

Trials:

Third or fourth time I want back to this bug I found a way to set the header – but then only to a static value with no way to change it depending on the tab selected. I did this by setting the header in my main stackNavigator like this:

export default createAppContainer(
 createStackNavigator(
  {
     UserTypeLoginScreen: { screen: UserTypeLoginScreen },
     Main: { screen: mainBottomNavigation,
       navigationOptions: ({ navigation }) => ({
         title: "Title here"
      })},
     Login: { screen: LoginScreen },

I also then tried to use the navigation state, which did not work as apparently navigation state is not present in “createBottomTabNavigator”, so this would not even run:

export default createAppContainer(
 createStackNavigator(
  {
     UserTypeLoginScreen: { screen: UserTypeLoginScreen },
     Main: { screen: mainBottomNavigation,
       navigationOptions: ({ navigation }) => ({
         title: `${navigation.state.params.title}`
      })},
     Login: { screen: LoginScreen },

Reading a bit more on React Navigation I found a site where someone suggested creating “StackNavigators” as these had “navigation state”. My initial trial with this however only got me in a mess where I ended up having 2 headers. My originalle formatted one but without any text as title and then one beneath it without formatting but now with text.

Solution:

I actually rolled back my changes as I abandoned them since they only made my problems worse. Researching a bit more I however found a suggestion on setting the header to null in my “main” stackNavigator. I though this might enable the underlying bottomTabNavigator to overwrite and present the header text. But setting it to null removed the header all together.

Remembering that I had a way to create 2 headers I now formed a solution in my head. If I could “hide” the normal header from the “main” stackNavigator once going into the bottomTabNavigator, then I could perhaps style the header to look exactly the same and then end up with a solution to my problem. And low and behold. After re-creating my discarded code on “stackNavigators” inside the “bottomTabNavigator” and styling the headers to look the same as my “main” “stackNavigator” then it finally worked!

Below is the code first for my “createBottomTabNavigator” with its independent “createStackNavigator” for each page to hold their own navigation state and hence header. And after that is the code from my “main” “createStackNavigator” where I hide the header so that each of the nested “stackNavigators” can show their own equally formatted headers. And then everything works!

const ProgramListStack = createStackNavigator(
{
   ProgramListScreen: {
     screen: ProgramListScreen
  }
},
{
   defaultNavigationOptions: {
     headerStyle: {
       backgroundColor: "#4EC3B2"
    },
     headerTintColor: "#fff",
  }
}
);

const PatientListStack = createStackNavigator(
{
   PatientListScreen: {
     screen: PatientListScreen
  }
},
{
   defaultNavigationOptions: {
     headerStyle: {
       backgroundColor: "#4EC3B2"
    },
     headerTintColor: "#fff",
  }
}
);

export const mainBottomNavigation = createBottomTabNavigator(
{
   ProgramListScreen: {
     screen: ProgramListStack,
     navigationOptions: ({ navigation }) => ({
       title: `Programs`
    })
  },
   PatientListScreen: {
     screen: PatientListStack,
     navigationOptions: ({ navigation }) => ({
       title: `Patients`
    })
  }
},
{
   defaultNavigationOptions: ({ navigation }) => ({
     // Removed for brevity
}
);
export default createAppContainer(
 createStackNavigator(
  {
     Main: {
       screen: mainBottomNavigation,
       navigationOptions: ({ navigation }) => ({
         // Set to null to hide header and have the bottomNavigator display its own  
         header: null
      })
    },
     Login: { screen: LoginScreen },
     // Removed for brevity
  },
  {
     defaultNavigationOptions: {
       headerStyle: {
         backgroundColor: "#4EC3B2"
      },
       headerTintColor: "#fff",
    }
  }
)
);