Code a reliable menu and tab-bar in a StencilJS + Ionic app

StencilJS is a great tool for making web apps, but it’s not always clearly documented. Here I go through how to (and how not to) include a working menu in an Ionic app that uses ion-router and ion-tab-bar.

Shows menu open on left side and tab bar present behind.
The app with a working tab bar and side menu.

TLDR: Below are the three relevant components. 🤙 Hope you like it.

The header component is used as the first element within the app-home and app-output components (which aren’t shown but can contain whatever you want). The reason I separated out the header is to reduce duplication and in my production version I use slots for additional elements that are shown only in certain tabs. App-home is the content that will show in tab 1 and app-output is for tab 2. If you only have the one menu there is no need to use the tags ‘menu’ and ‘menuId’ which would link the ion-menu-toggle and ion-menu otherwise.

How I got to this point

Firstly, in the Ionic you’ll notice that the ion-menu web component can be triggered a number of ways.

  1. By virtue of simply having the correct elements in your app. The ion-menu-toggle will find and toggle the nearest menu but no details are supplied about how this is done and what exactly the arrangement needs to be. This is what I eventually make, and is shown above.
  2. Finding the ion-menu component within the doc and calling it’s toggle() method. (not in the docs) This is what I ended up using within my ion-menu-toggle when I couldn’t get the suggested method to work initially.
<ion-button onClick={() => {document.querySelector('ion-menu').toggle()}}>
  1. Import the menuController object and call methods within a button. As shown in the documentation which I’ve copied and trimmed down below. This will be the starting point for discussion.

Notice also that the code for the main body is linked between the id tag and the tag contentId in the menu. In an app where you are trying to seperate code concerns, you will likely have this body separated into an entirely different component. It’s not clear from the docs why this is needed but if you cannot achieve this link you will have less than desirable behaviour.

I was able to get it working without this link but I had to use method 2 and as a result didn’t get the inbuilt swipe-to-open-and-close functioning on the menu. You had to click the toggle button.

For some reason I thought I’d try sneaking in a ion-nav component within the app-menu component. For ages I thought this had worked but I got flaky behaviour that sometimes (and 100% of the time in safari) resulted in this. 😰

Messed up menu with all page items inside it
Messed up menu with all page items inside it

So yeah - I don’t recommend that. I’d really like to learn about how the ion-nav component works in conjunction with the ion-router but there’s basically minimal documentation. 🤷‍♂️ Please more docs if you’re listening The ionic team.

The only way I was able to get it fully working was by including the empty div with an id=main in the app root as shown at the top. Without this you need to use method 2 and you wont get a swipe-able menu.

Also shout-out to Joshua Morony and his book on StencilJS, which has helped me greatly.