Custom Tab Navigator Using React Navigation & SVG

Matan Kastel
The Startup
Published in
4 min readSep 9, 2020

I’ve recently faced an issue at work where I needed to create a custom tab navigator. I would like to give a shout out to William Candillon. He has a great YouTube series called “Can It Be Done In React Native” where he demonstrates complex application animation using React Native.

Last year, he did a live challenge in which he had some parts of what I needed. I needed to create some similar things but without any animation for starters.

Introduction

I am going to showcase the following custom tab bar. I’d like to point out that I use D3 & React Navigation. If you want to read my post about using D3 & React you can do so here.

UX -> UI -> DX

The Set Up

We will be using d3-shape and react-native-svg packages. We are also going to use the React-Navigation package for the routing.

We’ll start by defining some routes to our application.

router file

Note that we set the tabBarVisible to false to hide the provided BottomTabNavigator since we are going to make our own <TabsUI /> component. This will allow us to have complete control over animations, shapes, icons etc.

The <TabsUI/>

In order to achieve the required result .We will have few components, all working together.

We start by defining the shape using d3-shape. We will create a line by using a line generator. We’ll divide our shape to 3 parts: left, center and right. We’ll start off with the easy parts, left and right. We know the tabWidth is based on the screen width, divided by the number of tabs we want to place. Since we are using SVG coordinate system the [0,0] point of the shape is top left corner. Keep in mind that we will use a constant value to store the tab bar height.

For the left part we define a line going from [0,0] to about the center [tabWidth * 2, 0]. For the right part we start a little bit after the center tab [tabWidth * 3, 0] going to the end [width, 0] then we close the shape by going down to [width, height] and back to start [0, height] closing the shape.

For the center part we will create a V-like shape by providing the values, going a little bit continuing the x-axis while going down up to half of the height, then taking up the values on the y-axis to 0 again while going continuing the path on the x-axis.

There are many curve functions, that can help us smoothing the connection between the points. We’ll use a curve function from d3 here are some examples.

If you wish you can experiment with this nice example.

Here is the code for the <TabShape /> Component using the described above.

TabShape - Creating a background, separate UI & Functionality
<TabShape />

Now that we have a background all we have to do is overlay the icon for the navigation on top and we are done.

We’ll create a <TabsHandler> component for that.

TabsHandler — Creating handlers, separate UI & Functionality

Notice that for the middle larger icon we do not render the tab SVG with a text and use Logo component. This logo component will be drawn on center, instead of the middle tab position. It would be a separated component so we can add a opening animation if we want to, later.

Put it all together

We now combine both of the components and lay them one over the other.

That’s it!

We now have a custom tab navigator. If we need to animate it - we have a full control over the shapes. This is while having the functional navigation working.

Ninja Developer

We used D3 for the complex shapes but kept the logic for the tabs separated. This is decoupling, while working in a team, is very recommended in cases where not all team members understand D3. While one team member handles the animations & creating the complex shapes of the tab bars, the other members can do the standard navigation functionality.

It is very important to know that I had a case where I needed to control the rendering completely. I needed to create some overlays that I could not done otherwise. If you don’t care for this and only want to render a custom tab you can use <Tabs.Navigator/> prop named tabBar where you can provide it with a render function that returns our updated <TabUI /> component.

You can find a working demo here, but keep in mind that it was slightly changed from the code snippets shown on the post. It is posted so you can have a general idea about routing.

If you like this post, you are more than welcome to check my other posts about React & D3, or Why I use React Spring.

If you have any questions you can contact me on twitter 🐦. I will try to get back to you.

Stay safe! ✌😷

--

--