How to build a nested drawer menu with React Native
Screen space is a precious commodity on mobile. The drawer menu (or “hamburger menu”) is one of the most popular navigation patterns that helps you save it while offering intuitive navigation. In this post, I will demystify how to build a nested (multi-level) drawer menu using React Native and React Navigation. 🔰
Try the live demo on mobile📱or on web. 🕸️
Navigation in React Native ⚛️
Navigation forms the backbone of a huge majority of apps built for production. The look and feel of navigation are important for driving use and engagement in mobile apps.
However, if you are React Native developer, there isn’t a clear opinion when it comes to building a navigation menu. React Native recommends a bunch of libraries for navigation. Each has its strength, depending on your needs, but there’s no one clear winner for all use-cases.
None of the navigation libraries currently support nested drawers out-of-the-box. But one of the libraries that provides a rich API to build custom solutions is React Navigation — a JavaScript-based navigation. It is strongly backed and maintained by the React Native community. This is what we’re going to use in this tutorial.
The use case 🕵️
I had to build a playground app to showcase a UI components library for React Native. It consists of eight different components, each supporting various props, and more than 50 different options.
It was not possible to show all options inside the drawer at one time without a multi-level drawer which would scope the options based on the selected component. I couldn’t find a ready-made solution for this, so I needed to build a custom one.
Base setup 👷
For the base setup, I’m assuming you already have a React Native project setup with either CRNA, Expo Kit, or React Native CLI. Make sure you have the react-navigation library installed with either yarn or npm. We’ll start right off with using the navigation API.
Feel free to check the getting-started guide before proceeding if you aren’t familiar with the React Navigation API.
We’ll start with an example similar to the one documented in the React Navigation’s DrawerNavigator official guide. We’ll create a simple drawer that has two drawer items: Home and Notifications.
Custom drawer content
React Navigation enables all navigators to do a lot of customizations by passing a navigator config as the second parameter. We’ll use it to render some custom content other than the stock drawer items.
DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)
We’ll pass a prop called contentComponent
to the config which would allow us to render custom content for the drawer. We’ll use that to show a header and footer along with the prevailing DrawerItems
from react-navigation
.
This potentially unlocks a lot of things that can be done by controlling what to render inside the drawer.
Creating screen mapping
We need to build a nested drawer for each component that we want to showcase. So let’s first register all the screens with the DrawerNavigator’s Config. We’ve created a separate screen mapping file for components. You can very well have your own convention, or define the object directly similar to the Home screen component.
The screen mapping consists of simple objects with screen property. The screenMapping
object looks something like this:
After registering all components, the drawer would look something like this:
This would render all the components along with their options. We have two main components: DataSearch and TextField. Each has options like “With Icon Position,” “With Placeholder,” and more. Our task is to segregate these into a list of only components (DataSearch, TextField).
Grouping outer drawer
A pattern I followed in the mapping was to use a delimiter _
to group together options from one component. For instance, the navigation keys I used were “DataSearch_Basic” and “DataSearch_With Icon Position”. This is exactly what is going to help us combine the options for a single component like DataSearch. We’ll evaluate uniquely all the components we need to show for the outer drawer.
We’ll create a util function to evaluate outer drawer list items to render.
This function will return an object with unique components for the main components like (DataSearch, TextField) that we’ll render on the screen with the help of the contentComponent
custom component. We’ll also maintain a boolean to determine the content rendered on the drawer at a particular instant.
The renderMainDrawerComponent
is just a function iterating over the keys of the components object. It renders custom outer drawer items built on top of simply Text
and View
from react-native. Check the full code here.
This will render the drawer like this:
Rendering the child drawer 🧒
Now, we need to show the options based on the component that is tapped. You might have noticed that in utils, we’re also extracting the start and end indexes of the component groups based on the delimiter pattern.
For instance, DataSearch screens start at index 1 (index 0 is Home screen) and ends at 3. TextField starts at 3 and end at 5. We’ll use these indices to magically slice the items
that are passed to DrawerItems
based on the selected component and its indices.
Now, after tapping on DataSearch, the drawer will yield into something like this:
We’ve also added a sweet back button which basically toggles a boolean to render the main drawer items. You can check the full code here.
Now, the only thing left to do is make the drawer items look cleaner by trimming the redundant component name. Again, the rich React Navigation API comes handy here.
There are various properties we can pass with navigationOptions
. A particular one we’re going to use here is the title
prop with the screen mapping. This will let us remove the part before the first delimiter. So, “DataSearch_Basic” will show as “Basic” only.
That’s all. We can add as many items we want based on the delimiter pattern. The playground app we’ve built consists of eight main components and over 53 total options.
Summary 📝
- Base setup: DrawerNavigation hello world from docs.
- Custom drawer content: Render drawer items with
contentComponent
. - Screen mapping: Define and register all drawers components.
- Group outer drawer: Read delimiter pattern to group drawer items.
- Rendering child drawer: Slice and render child drawer items.
Conclusion 🎬
We learned to build a multi-level drawer menu with React Native. We used React Navigation API to render a custom content component inside the drawer, and used the delimiter pattern for screen mapping. Use this pattern to build any level of nesting or conditional rendering for drawers.