Creating a custom Sidebar Tab Navigator with React Navigation

--

TL;DR: If you just want to see how to create the Sidebar Tabs Navigator, and ignore all of that juicy backstory, jump to the Creating the Sidebar Tab Navigator section of this post.

The full example project can be found here.

During the last two years of my career I’ve been developing mobile apps with React Native and, for the most part, it’ s been nothing but pretty straightforward designs and interactions. Everything was sunshine, flowers and general happiness.

However this month I’m creating an app for iPads, for the first time, and an unnexpected challenge presented itself. The clients wanted the app to have tabs… on a SIDEBAR.

Sidebar tabs example wireframe or, how I like to call it, “have you tried flexDirection: ‘row’?”.

Pretty simple, right? I mean, our team’s using React Navigation which is a very robust lib and it must have support for this kind of thing. Oh child, how I wish I could regain my lost innocence and have such pure thoughts. The reality is that the docs explaining how to create custom navigators are SUPER vague and didn’t help much. Stack Overflow has a few questions posted but I couldn’t find an answer that would help me create the component I wanted.

What’s left is to head to React Navigation’s canny.io and ask the project’s devs for official support and try to create the component myself.

Please upvote so our dev gods answer our prayers.

Creating the Sidebar Tab Navigator

Since the docs weren’t that helpful my eyes turned to the official GitHub repo, more specifically to the example section, and found this file. The part of the code that helps us is this little component right here:

Example of how to create a custom tab bar with React Navigation.

This section of the example code teaches us how to actually retrieve the current active screen and display it along with our custom tab bar. There’s also the need to create the tabs themselves (represented in the code by the CustomTabBar component), but for now let’s create a simple View with a background color, we’ll revisit this part of the code later.

Temporary custom sidebar tabs.

React Navigation’s docs tell us that there is a method specifically created to generate custom navigators.

This utility combines a router and a navigation view together in a standard way:

const AppNavigator = createNavigator(NavigationView, router, navigationConfig);

Let’s make use of this method (along with the provided TabRouter constructor) to generate elements that are compatible with React Navigation and add them to our navigation stack, like so:

const createSidebarNavigator = (routeConfigMap, sidebarNavigatorConfig) => {const customTabRouter = TabRouter(routeConfigMap, sidebarNavigatorConfig);return createNavigator(SidebarTabsNavigator, customTabRouter, {});};
Navigation stack.

Now that we know all of this the only thing left is to add flexDirection: 'row' to the View encapsulating both elements and voilà, the components are now placed correctly and are navigatable.

Our custom sidebar navigator on an iPad simulator.

Improving our sidebar

By this point most of the work is done, all that’ s left is to expand on the tabs themselves so they look better and can navigate between screens. To accomplish this the navigation and descriptors objects, that’re automatically passed when we use the createNavigator method, can be utilized by our tabs.

SidebarTabs.js
The final NavigationStack.js file.

The final product should look something like this:

Final SidebarTabNavigator.

Beautiful, don’t you agree?

Conclusion

Even if the official docs were not very helpful we were able to achieve the behavior we wanted with very little effort after some careful research and a quick dive into the source code for React Navigation’s examples.

One issue with this text’s code is that React Navigation’ s NavigationEvents element stops working. If navigation events are an essencial part of your app I recommend not implementing this solution for now.

I’ve created a thread on Stack Overflow searching for help, but so far no one posted an answer. When a solution’s found I’ll update this post, as well as the example project, to reflect the changes needed. But for now this approach solves my client’s needs for their app and it’s enough for me.

The full example project can be found here.

Thank you for reading.

--

--