Adding a Custom Tab Bar to Your Mini Program

George Borrelli
Shanghai Coders
Published in
6 min readMar 17, 2021
Photo by Maximilian Weisbecker on Unsplash

When I first started creating mini-programs, there was only a limited set of UI features available to developers. Over time, this feature set has gradually expanded to allow for fixed ‘native’ elements such as the tab bar to be swapped out and customized for purposes such as:

  • Displaying different tabs for certain user types
  • Personalizing the look of the tab bar and tab items

These needs can be met by setting our tab bar to custom and building it ourselves.

Today I will show you how to configure and create a custom tab bar and discuss some limitations that I came across while using one in a production project.

Step 1: Configure app.json

Let’s begin by enabling the custom tab bar feature in our app config file.

Open app.json and scroll down to your “tabBar” property.

Add a property to this object named “custom” with a value of true.

If you are creating your tab bar for displaying different tabs depending on certain user roles, you’ll also want to make sure that all of the pages you want to use as tab bar items are added to the tabBar “list” array.

Set custom: true in your app.json file to enable a custom tab bar

Setting the “tabBar” to custom disables the native tab bar and allows you to create a component that will be shown on all pages added to the “tabBar” list.

Step 2: Create the Custom Tab Bar Files

According to the documentation, we now have to create a component for the custom tab bar to use.

This component must be located in a specific folder called “custom-tab-bar”, where this folder is placed directly in your mini program’s root directory.

After creating the custom-tab-bar folder, right-click it from within the MP dev tools and create a new Component named “index”. The dev tools will generate 4 files and your folder structure should look like this:

Mini program folder structure with a custom tab bar component

If you’ve done everything correctly, your new custom tab bar should already be displaying the default “custom-tab-bar/index.wxml” text at the bottom of your page.

Step 3: Style the Custom Tab Bar

Now that our tab bar component has been created and is displaying on our pages, let’s make it actually look like a tab bar. We’re going to use code from WeChat’s official example to re-create the original tab bar.

While your dev tools are open, click on this link to open and import the example. You’ll want to copy the code from all of the files in the example’s custom-tab-bar folder over to your project.

Example custom tab bar. It looks exactly the same as the native tab bar

Notice that the example code uses cover-view and cover-image instead of view and image components. This is because some native components such as a camera, canvas, or textarea will render on top of anything except a cover-view, and you wouldn’t want your tab bar disappearing under them.

<cover-view> and <cover-image> can display on top of native components while <regular view> and <image> cannot

Step 4: Implement Tab Bar Logic

Now that we have a basic structure and style for our tab bar, open the component’s index.js file and replace the “list” objectArray’s values for the pagePath, iconPath, selectedIconPath, and text for each tab item with the values your project will use.

Replace all default list elements with ones for your own tab bar items

If your tab list is going to be dynamic, you will need to use a global store to make sure that each tab bar instance is updated with the correct list of tab bar items after an authentication flow, for example. If you’re new to global stores, I previously wrote about implementing a global store into your mini program here:

This file also contains one method called switchTab, which navigates to the tapped page and sets the correct tab index in the component’s data. If your pagePath is correctly configured for each tab, you should be able to navigate to all of your tab pages.

After you tap on a tab, you will notice that the ‘active’ icon and text briefly change to the correct tab, but then changes back to the first tab. The is because our tab bar is now a component, and in the mini-program framework, components are children of the page they are on.

There are currently no global components that can wrap the entire mini program. This means that on each of our pages the tab bar is displayed on, we are actually rendering a brand-new tab bar component, and our component’s initial active tab is set to the first one.

To mitigate this issue, we have to set the correct tab bar index on each of our pages. If you looked at any of the pages in the example code, you will see that there was code added to the show() page lifecycle method:

Note: The example uses components as pages, but we will stick to the traditional Page() constructor on our pages for now. The pageLifecycles object in this component accepts all of the properties which normally occur on a regular page.

This code uses a global mini program function called this.getTabBar(), which gets the instance of the tab bar component attached to the current page, and sets the value of its active tab index.

You will have to copy this code onto each of your pages, making sure to set the correct tab index according to the order of your tabs. If you are implementing a dynamic tab list, you will have to add in your own logic to calculate the proper tab index for the current page.

Now when you tap on each tab, the correct active tab is set by the page. You’ve successfully created a custom tab bar!

Limitations

Of course, customization has its trade-offs. While developing a custom tab bar for a mini-program in production, I came across a few things that made me feel like the tab bar was mostly added as an afterthought:

  • You must now compensate for the tab bar height on all of your tab pages (add bottom margin or padding to the page’s style)
  • Once a tab is tapped, the tab bar flickers a bit as colors and image paths are changed*
  • The tab bar re-renders on every page, displaying a blank tab bar for a certain period of time. Heavy mini-programs can experience blank bars for an extended time*
  • You must set the active index of the tab bar on each page, or use a global store to inject the correct index into each tab bar instance
  • These issues are more prevalent on Android devices. Communication between the service and view layers on iOS devices is much faster

Here is my example code for this project which you can click to import with your developer tools (enter appId if you want to view it on your phone):

For more information, please visit shanghaicoders.com

--

--

George Borrelli
Shanghai Coders

WeChat developer and Chinese speaker currently living in Shanghai. Founder @ChatDevs