Understanding Ionic’s Side Menu

posted in: Uncategorized | 64

In the last couple of years, the sliding-out side menu (sometimes known to as a Navigation Drawer) has become a very popular pattern for apps. It is a win for app developers as it is an easy way to include many different features where a tabbed interface does not suffice. Users have become used to the pattern through use of mobile apps (and increasingly responsive or mobile websites) and so it is usually a safe pattern to use in your apps.

Ionic luckily has a side menu directive which is easy to implement, user friendly, and very performant. In this tutorial we’ll take a look a the ionic-start-sidemenu project on Github and break it down piece by piece to get a good understanding of how it works.

Sidemenu Directives

The ion-side-menus directive is made up of a few parts. First, the main directive that wraps everything related to the sidemenu.

<ion-side-menus>

</ion-side-menus>

Inside of here, we’ll define our ion-side-menu (The actual side menu) and our ion-side-menu-content (The main content).

<ion-side-menus>
	<!-- Main content -->
	<ion-side-menu-content>

	</ion-side-menu-content>
	
	<!-- Left Side Menu -->
	<ion-side-menu side="left">
	
	</ion-side-menu>
</ion-side-menus>

You’ll notice here we specified for the menu that it should be on the left side. This value can also be right. Additionally, if we wanted a menu on both sides, we could have a ion-side-menu for each side.

<ion-side-menus>
	<!-- Main content -->
	<ion-side-menu-content>

	</ion-side-menu-content>
	
	<!-- Left Side Menu -->
	<ion-side-menu side="left">
	
	</ion-side-menu>
	
	<!-- Right Side Menu -->
	<ion-side-menu side="right">
	
	</ion-side-menu>
</ion-side-menus>

One additional thing to note is that we can change the behavior of the sidemenu to always display as a second column on tablets (like the settings left menu on an iPad.) To do this, we use the expose-aside-when attribute on our ion-side-menu.

<ion-side-menus>
	<!-- Main content -->
	<ion-side-menu-content>
	</ion-side-menu-content>

	<!-- Left Side Menu -->
	<ion-side-menu expose-aside-when="large">
	</ion-side-menu>
</ion-side-menus>

The possible values on this attribute are a media query specifying min-width or the keyword large which is a shortcut for (min-width:768px). The above example if 768px or greater will show the sidemenu next to the content whereas if the width is less than 768px, it will act as a normal slide-out side menu.

Sidemenu Index

Let’s beginning digging into the sidemenu start project. The project is made up of the main index.html page, a menu.html template which serves as our template and contains our sidemenu code, as well as templates for each view. Additionally, we have an app.js for our app’s configuration and controllers.js for our controller code.

The idea here is our index.html defines our app and creates kind of a shell. The menu.html defines the structure of our app and inside of this structure is where the views live. Let’s take a look at our index.html page:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
		<title></title>

		<link href="lib/ionic/css/ionic.css" rel="stylesheet">
		<link href="css/style.css" rel="stylesheet">

		<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
		<link href="css/ionic.app.css" rel="stylesheet">
		-->

		<!-- ionic/angularjs js -->
		<script src="lib/ionic/js/ionic.bundle.js"></script>

		<!-- cordova script (this will be a 404 during development) -->
		<script src="cordova.js"></script>

		<!-- your app's js -->
		<script src="js/app.js"></script>
		<script src="js/controllers.js"></script>
	</head>

	<body ng-app="starter">
		<ion-nav-view></ion-nav-view>
	</body>
</html>

You’ll notice how little there actually is here. As stated above, the idea here is that we have a shell for our app by marking the body with the ng-app attribute. (Fun fact: Angular uses Angular for it’s internal directives. ng-app is an Angular directive. Mind blown.)

menu.html

Let’s take a look at the menu.html file. Remember, this file is our main template and will define both the menu and where the content will fit in.

<ion-side-menus>

  <ion-side-menu-content>
    <ion-nav-bar class="bar-stable nav-title-slide-ios7">
      <ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button>
    </ion-nav-bar>
    <ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>
  </ion-side-menu-content>

  <ion-side-menu side="left">
    <header class="bar bar-header bar-stable">
      <h1 class="title">Left</h1>
    </header>
    <ion-content class="has-header">
      <ion-list>
        <ion-item menu-close ng-click="login()">
          Login
        </ion-item>
        <ion-item menu-close href="#/app/search">
          Search
        </ion-item>
        <ion-item menu-close href="#/app/browse">
          Browse
        </ion-item>
        <ion-item menu-close href="#/app/playlists">
          Playlists
        </ion-item>
      </ion-list>
    </ion-content>
  </ion-side-menu>
</ion-side-menus>

So, you’ll see we have our ionic-side-menus, ion-side-menu-content, and ion-side-menu pattern. Visually, this is what our app structure looks like:

sidemenu diagram

As shown in this diagram, the structure of the markup and the final outcome are very similar.

ion-side-menu-content

In our ion-side-menu-content, we have a ion-nav-bar (with an ion-nav-back-button) and a ion-nav-view.

<ion-side-menu-content>
    <ion-nav-bar class="bar-stable nav-title-slide-ios7">
      <ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button>
    </ion-nav-bar>
    <ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>
</ion-side-menu-content>

The ion-nav-bar creates a header bar at the top of our app that automatically contains the title (soon to be view-title in Beta 14) of the current view. It also contains a ion-nav-back-button which will generate a button then when clicked will go back a state.

The ion-nav-view is where our child states (the views of our app) will be inserted and live. Note that we have given it a name attribute of menuContent. This name will be used to reference to this ion-nav-view when we are building our states in the app’s config.

ion-side-menu

In the ion-side-menu half of our menu.html, we have a header (a visual element) and a list of ion-item where each item is a side menu link.

<ion-item menu-close href="#/app/search">
  Search
</ion-item>

Notice that these links are decorated with a attributes: menu-close.

menu-close is an Ionic Directive which causes the element, when clicked, to close the side menu. Without this attribute, clicking on the link will cause a the navigation to the new view, but will leave the sidemenu open. It will also clear the history stack and does not cause an animation between views with navigating. Due to the clearing of the history stack, the back button will not show when you navigate to the next state. (Official Docs)

Child View

Now that we have our app’s structure and main template, let’s take a look at what the child views (the actual content views of the app) look like.

<ion-view title="Playlists">
  <ion-nav-buttons side="left">
    <button menu-toggle="left" class="button button-icon icon ion-navicon"></button>
  </ion-nav-buttons>
  <ion-content class="has-header">
    <ion-list>
      <ion-item ng-repeat="playlist in playlists" href="#/app/playlists/{{playlist.id}}">
        {{playlist.title}}
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

This is playlists.html, the default view in our app. Two interesting things to note here are that we can specify additional buttons that should be in the ion-nav-bar while we’re in this view and that we are specifying the title within this view. Everything in these template files should be wrapped in the ion-view tag, and the actual content for the view in a ion-content tag.

Controllers

For this app, we have one main controller that applies to every view (because it is the controller for our parent state, menu.html) and then a controller for any child states that need a controller. These are pretty straight forward as far as Ionic/Angular controllers go, so we won’t go much into that.

Configuration

Here’s where the magic happens. Using the Angular-UI router, we want to define our menu.html (and our main controller, AppCtrl) as an abstract state. From the Angular-UI docs an abstract state “…can have child states but can not get activated itself. An ‘abstract’ state is simply a state that can’t be transitioned to. It is activated implicitly when one of its descendants are activated.”. This is exactly what we want. We want our user to navigate to the actual views, but to inherit the main layout from the parent abstract state.

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('app', {
      url: "/app",
      abstract: true,
      templateUrl: "templates/menu.html",
      controller: 'AppCtrl'
    })
	.state('app.playlists', {
      url: "/playlists",
      views: {
        'menuContent' :{
          templateUrl: "templates/playlists.html",
          controller: 'PlaylistsCtrl'
        }
      }
    });

Our base URL, as configured here, is /app. Notice our child state uses dot notation where to the left of the dot is the name of the parent state and to the right of the dot is the name of the child state. In our url, we don’t need to tell the router to go to “/app/playlists”, as it already knows to do this.

Remember that menuContent name attribute on the ion-nav-view in the parent.html page?

<ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>

Here in the router, on the child state, we are defining that it should put it’s content (using the template file playlists.html and the controller PlaylistsCtrl) in that ion-nav-view.

Conclusion

While there is a lot going on in this kind of an app structure and a lot of concepts to wrap your head around, it becomes much easier to understand when you break it down piece by piece into bit sized pieces. Need further clarification or have a request for another Ionic post? Feel free to comment below or follow and mention me on twitter (@andrewmcgivery).

More Reading

Structure of an Ionic App
Creating Views with Ionic
ion-side-menus Docs
ionic-start-sidemenu project on Github
Angular UI Nested States Docs

My name is Andrew McGivery. I currently work full time as an application developer at Manulife Financial in Canada. My current passion is building and leading highly engaged teams where employee happiness, learning, and growth is a priority.

64 Responses

  1. Is it possible to create separate page for only side menu content? Because I have more than 30 page in application and every page has same side menu. So It is good if I can set separate page for side menu.

    • Hello,

      If you follow this tutorial, your side menu is contained within one file and each of your other views (or pages) are contained in separate files.

  2. Is it possible to create a nested view within the ‘menucontent’ view? I have a button that fires a cordova barcode scanner. I want to show the returned result from the scanned barcode as a nested view at that level.

  3. Hi, thanks for the post. I was trying to use your code, but there is something missing, or I just didn’t get. If I try to use the cod above it doesn’t work, so would be possible to have the source code in order to see what you did? Thank you.

  4. Thanks Andrew for this “understanding” post, it’s a way more clear than ionic’ doc, each of their 3 example projects should be explained like you did so that developers could understand good practices et techniques used.

    • Hey Jiyuu,

      Thanks so much for your comment. I’m so glad I could be of help. 🙂

      It’s my goal to cover most if not all of the Ionic Directives, giving each of them a long form explanation of how to use it and why.

      If you have any requests, let me know! 🙂

  5. Is it possible to create a sign in screen then after a person has signed in display the sidemenu and content?

    • Hello Amy,

      Thanks for your comment.

      Yes it is possible, and pretty easy too!

      Basically, you want to set up your app so that the default route in your login page. Your logic page (state) will NOT be a child of your parent sidemenu state.

      Here’s a CodePen example of a sign-in page followed by tabs: http://codepen.io/ionic/pen/CbBsA

      Observe the routing: The signin and forgotpassword states are not children of the tabs state.

      It would work identically to this for sidemenus.

      Let me know if you need any more assistance!

      • Thanks for your reply.

        Yep I have tried this but not sure what I am missing as the sign in form is not displaying :/ but the original application is

  6. Ok sorry replied too soon my localhost was just being slow in refreshing haha it works thabk you 🙂

  7. Deepak Jain

    Hello Sir,
    I am in new in ionic I have a query about side-menu,
    I want to change background color of each ion-item color with in ion-list.
    Please help me!
    Thank you !

  8. do you have any idea about how to use side menu + tabbed view at the same time and not sliding tabs. tabs should be static.

  9. This article is the best I have read ever in ionic framework. Its an eye opener. Thanks a lot for taking me out of the dark

  10. I need some help. I have an app that displays a long list. After you login the first time it works. But if you log out and log in again, the list is not rendered. I have to delete the app from recent apps and start over to make it work again. Any idea why is that happening to me? Thank you

  11. Why I can’t show my child view in doing this??

  12. How can I add an icon (that differs per page) on the right side of the header, opposite of the menu icon? From what I can tell, all the logic is in the single file (menu.html).

    E.g. I want to add a ‘new message’ or ‘add friend’ icon to the header. Thanks!

  13. Thanks Andrew, great article, getting started with both AngularJS and JS and ionic (!) this is a GREAT source of…understanding. cheers

  14. Derek Hannah

    I get this error and I think its because the side menu, it happens when I click a side menu navigation link

    typeerror: ‘null’ is not an object (evaluating ‘content.offsetx’)

    ever see this?

  15. Hi Andrew,

    A: Is it possible to have the navbar sidemenu button invisible on back views but maintaining the side menu. Users could still drag the content to reveal te side menu?

    B: Is it possible to have the side menu dragged “above” the main content?

  16. Thanks for the article Andrew.

    I am stuck with a problem using Ionic’s side menu.

    Imagine that I have a side menu set-up with two pages linked, Page A and Page B.

    I’ve added a button into Page A which should lead the user to Page B. However, instead of using the parent view, Page B is rendered with a back button on the navigation bar. Is there any way I can direct the user to Page B while still having the parent menu bar showing?

  17. Matheus Abreu

    Hi Andrew. This is a great tutorial!
    So, how to change menu item height manually?
    I set via CSS class, but it`s not working in iOS.
    I appreciate your answer.

  18. Hi Andrew! It’s a great post. I have implemented an ionic app that uses side menu once you login in. However, in some views (child views like app.playlists) i would like to hide the nav bar to obtain more space in my mobile app.
    What is the way for doing that?

    Thank you!

  19. xantilon

    Hi Andrew,
    I find the width of the side-menu to small. But setting a width kind of breaks the functionality. Is there a way to change the width?

  20. Seems like nav-clear is no longer present in ionic 1.0.0.

    BTW do you know why side-menus create new stacks in $ionicHistory?

  21. Hi Andrew,

    The Ionic framework uses the angular-ui-router module for handling routes and defining states (including nested states and nested views). So, you should only use:

    Playlists

    Or:

    $state.go(‘app.playlists’);

    To transition between states and NOT ‘href’ (see menu.html).

    Take a look at this Plunker which addresses the issues with Ionic’s side-menu starter template:

    http://plnkr.co/edit/pGwucVrTBDxSvw6z092h?p=preview

    And: http://robferguson.org/2015/07/19/using-ui-router-for-handling-routes-defining-states-and-sharing-data-between-views/

    Cheers
    Rob

  22. Hello, first of all, sorry for my English is bad. I would like to ask how I can hide a side menu in any of the views (independent html), thanks !!!!

    • Are you asking how you, for a specific view, hide the Side Menu button? Is this view totally independent or does it rely on the previous history stack?

  23. I follow your tuto but I can’t use controller alias in routes, I tried insert something like this:

    .state(‘app.playlists’, {
    url: “/playlists”,
    views: {
    ‘menuContent’ :{
    templateUrl: “templates/playlists.html”,
    controller: ‘PlaylistsCtrl’,
    controllerAs: ‘PCtrl
    }
    }
    });

    In the view I put a {{PCtrl.teste}} (of course that this exists in PlaylistsCtrl.js file)

    But nothing works 🙁
    Any Idea how can I use controller aliases ?

  24. hi andrew, nice tutorial.

    Is it possible to create different menu with different page?
    I mean, when i on the page home, side left menu with menu home.
    when i on the page shopping, side left menu with menu shopping.

  25. Levente Kosa

    Hi, how can I add back button to the second level?

  26. I don’t like the top bar of the slide menu. Is it possible to hide it and customize it?

  27. hi, It would be great help to me if you reply to this post.

  28. Moses Asiago

    I couldn’t understand the docs until I got this post.Thanks alot @Andrew

  29. Thank you

  30. Thank you for this …It help me a lot.

  31. Using Ionic’s Creator I added a Side Menu but it only appears on my first page. As soon as I navigate away it’s gone, replaced by a back button. Would be nice to keep it I would think.

  32. Iyoke Ose

    Hey, Thank you for this. Your explanation is really broken down and on point.

  33. Thanks for your article!
    Could you tell me if it is possible to navigate between menu items? Let’s say that I have 2 items in menu: Home and News. When user goes to news (list) he can tap on news to see details. And now on news details I want to add “Home” button and move user to Home page (first item from main menu). When I use $state.go() or href=”#/index.html/home” new screen is added to stack and I see back button (back to news details). But I don’t want this button there – I want exactly the same behavior as when user taps on Home in side menu.

  34. Great article, very clear en helpul, Finally I understood this thing named “Side menus” in Ionic 🙂 thanks

Leave a Reply to uğur mirza zeyrek Cancel reply