Allow multiple menus

This question seems related, but is sadly unanswered and also seems to be Ionic+Angular: How to make multiple side menus working in a mobile browser

My app uses a navigation menu that allows switching between different pages. And depending on the page there’s also a context menu.

I can’t figure out how to make these two IonMenus coexist.
The goal is to have two IonMenuButtons in the page header. One on the left, for the navigation menu. The other on the right for the context menu.

To create a simple example, I set up a blank project with ionic start and added [two of the example menus from the docs page][1] next to the router. Now <App/> looks like this:

const App: React.FC = () => (
  <IonApp>
    {/* */}
    <IonMenu side="start" menuId="first" id='first' contentId="router-outlet">
      <IonHeader>
        <IonToolbar color="primary">
          <IonTitle>Start Menu</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonList>
          <IonItem>Menu Item</IonItem>
        </IonList>
      </IonContent>
    </IonMenu>

    {/* */}
    <IonMenu side="start" menuId="custom" id="custom" contentId="router-outlet">
      <IonHeader>
        <IonToolbar color="tertiary">
          <IonTitle>Custom Menu</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonList>
          <IonItem>Menu Item</IonItem>
        </IonList>
      </IonContent>
    </IonMenu>
    {/* */}
    <IonReactRouter>
      <IonRouterOutlet id="router-outlet">
        <Route path="/home" component={Home} exact={true} />
        <Route exact path="/" render={() => <Redirect to="/home" />} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
);

As you can see, the router has only a single route. In the header of that page, I would like to place two IonMenuButtons. Since that doesn’t work, I’m replacing one of them with a simple button:

const Home: React.FC = () => {
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start">
            {/* <IonMenuButton menu="custom" autoHide={false} /> */}
            <IonButton
              onClick={() => {
                (document.getElementById("custom") as any).open();
              }}
            >
              <IonIcon slot="icon-only" icon={star} />
            </IonButton>
          </IonButtons>
          <IonTitle>Double menu</IonTitle>
          <IonButtons slot="end">
            <IonMenuButton menu="first" autoHide={false} />
          </IonButtons>
        </IonToolbar>
      </IonHeader>

      <IonContent></IonContent>
    </IonPage>
  );
};

Now, this code has a variety of problems:

  • it is not possible to have two IonMenuButtons in the same header (in Home.tsx). Only one of them is rendered, the second one disappears.
  • it is not possible to have two Menus, only the second menu becomes available. In App.tsx I’ve placed the Menu with menuID first before the Menu with menuID custom. Only this second menu with id custom can be opened. Both the IonMenuButton and my hacky workaround button only work when pointing to custom. Switching the order in App.tsx makes only first work.

Link to SO question: javascript - ionic: how to allow multiple menus? - Stack Overflow

Well, turns out each menu needs a unique side property. It seems not possible to have multiple menus flow in from the same side.

If this is really the solution, I would say the docs are wrong. In the menu example here, there are multiple menus with overlapping side properties: https://ionicframework.com/docs/api/menu

I’ve spent a lot of time with the code from that example and was not able to make it work.

But the docs also mention an elusive MenuController. This seems entirely undocumented. Can someone explain what it does?

Hopefully you got it to work by now but since I was also stuck on this and want to save future googlers the hassle Let me tell you what I did. I used the documentation of V3 where the MenuController is actually documented. It seems you have to enable menu’s if you want to have multiple menu’s from the same side.
I do it like this:

constructor(private menu: MenuController){}

async openMenu(menuId: string) {
    await this.menu.enable(true, menuId);
    await this.menu.open(menuId);
  }

now if you call openMenu with the menuId it actually does open. Good luck to anyone finding this.

2 Likes