Side Menu pattern became very popular several years ago on mobile devices and tablets, it’s also known as Navigation Drawer or Sliding Menu. It works as a single fixed menu (or a set of two fixed menus) that will slide out from any page edge. A Side Menu can also be used in combination with the body moving to the left or right side (body is than “pushed”).
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

Table of Contents

Click here if you want to see other tutorials; or articles about Ionic themes, templates, plugins ...

Example

 
Demo
 
Working embede example
 
Ionic Side Menu Pattern
 
HTML
 
<html ng-app="myApp">
  <head>
	<meta charset="utf-8" />
	<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
	<title>Ionic Framework Example</title>
	<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet"/>
	<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
	<script src="app.js"></script>
  </head>

  <body ng-controller="HomeCtrl">

    <ion-side-menus>
      
      <ion-pane ion-side-menu-content>
        <ion-nav-bar class="bar-balanced nav-title-slide-ios7">
        <ion-nav-buttons side="left">
          <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button>
        </ion-nav-buttons>  
        </ion-nav-bar>
        <ion-nav-view></ion-nav-view>
      </ion-pane>

      <ion-side-menu side="left">
        <ion-header-bar class="bar bar-header bar-dark">
          <h1 class="title">Filter Movies</h1>
        </ion-header-bar>
        
        <ion-content has-header="true">
          
          <div class="list">
          
            <ion-radio ng-model="selected.score" ng-value="{{sort.score}}"  ng-repeat="sort in sorting">{{sort.name}}</ion-radio>
          
          </div>
          
        </ion-content>
      </ion-side-menu>
      
    </ion-side-menus>
    
    <script id="home.html" type="text/ng-template">
     <ion-header-bar class="bar bar-header bar-dark">
        <h1 class="title">Search The Movie Database</h1>
      </ion-header-bar>
      <ion-content>
        <label class="item item-input">
          <i class="icon ion-search placeholder-icon"></i>
          <input type="search" placeholder="Search" ng-model="selected.movieName" ng-change="searchMovieDB()">
        </label>
        <ion-list>
          <div class="list">
  
            <a ng-repeat="movie in movies  | filter: greaterThan('vote_average')" href="#/movie/{{movie.id}}" class="item item-thumbnail-left">
              <img ng-src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';">
              <h2><strong>{{movie.original_title}}</strong></h2>
              <h4>Release Date: <strong>{{movie.release_date}}</strong></h4>
              <h4>Average score: <strong>{{movie.vote_average}}</strong></h4>
            </a>
  
          </div>
        </ion-list>
      </ion-content>
    </script>
  </body>
</html>
 
JavaScript
 
var app = angular.module('myApp', ['ionic']);

app.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('home', {
      url: '/',
      templateUrl: 'home.html'
    });  
  $urlRouterProvider.otherwise('/');
});

app.factory('Movies', function($http) {
  var cachedData;
 
  function getData(moviename, callback) {
 
    var url = 'http://api.themoviedb.org/3/',
      mode = 'search/movie?query=',
      name = '&query=' + encodeURI(moviename),
      key = '&api_key=470fd2ec8853e25d2f8d86f685d2270e';
 
    $http.get(url + mode + key + name).success(function(data) {
 
      cachedData = data.results;
      callback(data.results);
    });
  }
 
  return {
    list: getData,
    find: function(name, callback) {
      console.log(name);
      var movie = cachedData.filter(function(entry) {
        return entry.id == name;
      })[0];
      callback(movie);
    }
  };
 
});

app.controller('HomeCtrl', function($scope, $ionicSideMenuDelegate, Movies) {
  
  $scope.sorting = [{score: 9, name : 'Score more then 9'}, 
                    {score: 8, name : 'Score more then 8'}, 
                    {score: 7, name : 'Score more then 7'}, 
                    {score: 6, name : 'Score more then 6'}, 
                    {score: 5, name : 'Score more then 5'}, 
                    {score: 4, name : 'Score more then 4'}, 
                    {score: 3, name : 'Score more then 3'}, 
                    {score: 2, name : 'Score more then 2'}, 
                    {score: 1, name : 'Score more then 1'},                     
                    {score: 0, name : 'Show me every movie'}];  
                    
  $scope.selected = {
    score : 0,
    movieName : 'Batman'
  }
                    
  $scope.openMenu = function () {
    $ionicSideMenuDelegate.toggleLeft();
  };
  
  $scope.greaterThan = function(fieldName){
      return function(item){
        return item[fieldName] > $scope.selected.score;
      }
  }  
  
  $scope.searchMovieDB = function() {
 
    Movies.list($scope.selected.movieName, function(movies) {
      $scope.movies = movies;
    });
     
  };
  
  $scope.searchMovieDB(); 
});
 

Side menu overview

 
Side menu pattern directive is formed from several sections. First section is a main directive container:
 
<ion-side-menus>

</ion-side-menus>
 
Inner content is formed from two distinct containers. They should usually look like this:
 
<ion-side-menus>
    <ion-side-menu-content>
        <!-- Main application content should go here -->
    </ion-side-menu-content>
	
   
    <ion-side-menu side="left">
        <!-- Left Side Menu content should go here-->	
    </ion-side-menu>

    <ion-side-menu side="right">
        <!-- Right Side Menu content should go here-->	
    </ion-side-menu>
</ion-side-menus>
 
Side menu content container can hold everything like classic ion-page. For example, working example menu content container looks like this:
 
<ion-side-menu side="left">
    <ion-header-bar class="bar bar-header bar-dark">
        <h1 class="title">Filter Movies</h1>
    </ion-header-bar>

    <ion-content has-header="true">
	  
        <div class="list">
            <ion-radio ng-model="selected.score" ng-value="{{sort.score}}"  ng-repeat="sort in sorting">{{sort.name}}</ion-radio>
        </div>
	  
    </ion-content>
</ion-side-menu>
 
Main application content is not defined in the ion-side-menu-content directive directly. Magic is instead done through AngularJS routing system. This is because Slide menu has a bigger priority than other application content. What would normally be shown first is now shown inside a ion-side-menu-content directive. That includes Ionic navigation bar (ion-nav-bar) and application navigation (ion-nav-view). This is how it looks in above working example:
 
<ion-pane ion-side-menu-content>
  <ion-nav-bar class="bar-balanced nav-title-slide-ios7">
    <ion-nav-buttons side="left">
      <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button>
    </ion-nav-buttons>  
  </ion-nav-bar>
  <ion-nav-view></ion-nav-view>
</ion-pane>
Continue Reading

  • Mark

    This is not working on Android 4.4.4 and Android 4.4.2. Do you have the same problem? It’s working on device Chrome browser. But not working on webview, tested with XDK App Preview and Ionic View. It’s working fine on iOS and Android 4.2.

    • Unfortunately, I don’t have any older Android device with me to test this, only 5+. My advice, go to official Ionic framework forum and ask this question. They will give you an answer very quickly.

  • Mark

    already open an issue. Thanks for your great blogs. Alway enjoy learning from your blogs. Keep up the good work and have a nice day.

  • Dmitry Isakov

    I also got an issue. I have a complex app with $stateProvider for routing. All the states are ok, except one – that uses two side menus.
    As for those side menus – everything is ok. But there is the problem with scrolling in the main content area.

    • My advice, go to the official Ionic forum and ask this question. Also, if you can prepare a working example we can use torecreate this problem.