Where to place an IonMenu (in the code)

short version:
I would like to have the same IonMenu in all my IonPages. Is there a way to move the menu above the pages, maybe next to the routing?

How do I set this up properly?

Detailed version:

My app has an IonMenu that is used to navigate between routes. It has a list of entries, each of them an IonItem that links to a route like ‘/home’, ‘/config’, etc.

Here’s a mock up of the current state

<router>
  <route path="/home">
    <lots of layout code for the menu>
    <page>
  </route>
  <route path="/about">
    <same menu code again>
    <another page>
  </route>
  ...
</router>

So this is horrible code duplication, the same code for the menu is duplicated on each page.

As far as I can see, there would be two solutions:

  • make a custom component for the menu. Then it’s only a single tag (and I would have to pass in the content-id via props)
  • move the menu up, above the router

I would prefer the second solution. Because the menu really is the same everywhere, it doesn’t depend on the routes. So I think it should be specified outside of the routing, as a sibling to the router. That would mirror the structure of the UI.

As far as I understand, there are the following requirements:

  • The IonMenu needs to be given a contentId. I think this should be IonRouterOutlet. The contentId specifies an element on which to listen for swipe actions. And I want that element to be the output of the routing.
  • There needs to be a toolbar with the IonMenuButton. I think this should go into an IonHeader. Intuitively I would place this header next to the IonMenu, as another sibling to the router. But the documentation says that: It’s important to note that ion-header needs to be the one of the three root elements of a page. And I’ve got the impression that they mean an actual literal IonPage here.
  • Every Route must be an IonPage and IonPages must not be nested inside of each other.

I tried placing the IonHeader next to the routing, but then the pages and the header overlap each other. This doesn’t seem to work. So I moved the header inside of the IonPage and came up with the following code (simplified to provide a minimal example):

App.tsx:

 <IonApp>
    <IonMenu side="start" contentId="main-content">
      <IonList>
        <IonItem routerLink="/home">
          <IonLabel>home</IonLabel>
        </IonItem>
        <IonItem routerLink="/config">
          <IonLabel>config</IonLabel>
        </IonItem>
      </IonList>
    </IonMenu>

      <IonReactRouter>
        <IonRouterOutlet id='main-content'>
          <Route path="/home" component={Home} exact={true} />
          <Route path="/config" component={Config} exact={true} />
          <Route exact path="/" render={() => <Redirect to="/home" />} />
        </IonRouterOutlet>
      </IonReactRouter>
  </IonApp>

Home.tsx:

    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start">
            <IonMenuButton></IonMenuButton>
          </IonButtons>
          <IonTitle>Routing Menu</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonButton routerLink="/config">To the config!</IonButton>
      </IonContent>
    </IonPage>

Config.tsx (this one without the menubar)

      <IonPage>
        <IonContent>
          <IonButton routerLink='/home'>To the home!</IonButton>
        </IonContent>
      </IonPage>

This code doesn’t work. If I transition between routes with the buttons, they are changed properly, with a small animation. But if the menu is used for navigation, the page flickers and seems to re-render completely. There is no transition animation between the pages.

What is the correct way to do this?

Here is a small video of the behaviour.
When using buttons for routing, the animations look ok.
With the menu it somehow reloads.

ezgif-3-ceb71c97272f

Take a look at the menu starter project for a proper menu structure.

ionic start myApp menu

A menu should exist at a root point, and not be included in multiple pages.

Sounds good, but there is no such starter template.

ionic start menuApp menu

Oh but there is sidemenu. And that sample looks great.

I think that fixes it. Thanks !