How to Build an Off-Canvas Navigation With jQuery.mmenu
This tutorial will take you on a quick tour of jQuery.mmenu, a jQuery plugin which helps create extensive website navigation. As we examine it, we'll see how we can use this plugin to build an off-canvas menu from scratch.
What is jQuery.mmenu?
For the best description of jQuery.mmenu, we’ll head over to its Github page:
“The best jQuery plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and webapp.
The jQuery.mmenu plugin is highly customizable and comes with many add-ons (e.g. counters and dividers) plus extensions (e.g. effects and page shadows). For those who prefer, it’s available as a Wordpress plugin, and it works well in a wide range of browsers!
Getting Started With jQuery.mmenu
To begin with, you’ll have to grab a copy of the library. This can be done by visiting its official page, through a package manager (e.g. Bower), or a CDN (e.g. cdnjs).
Once downloaded, you’ll have to include the necessary CSS and JS files in your pages.
Please note that depending on the menu you want to build, different assets might be required. For example, an off-canvas menu requires the jquery.mmenu.css
(or its minified version) and jquery.mmenu.js
(or its minified version) files. Should you want to modify the default behavior of the menu (e.g. move its position to the right), you’ll also have to include the files which are related to the “off-canvas” add-on. If that seems confusing and you don’t want to worry about which are the required files, go ahead and use the “all” files (i.e. jquery.mmenu.all.css
and jquery.mmenu.min.all.js
) into your projects.
In our demo, we’ll import the “all” files via a CDN. The head
element of our page will reference the “all” CSS file:
1 |
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.3.4/css/jquery.mmenu.all.min.css'> |
In the same way, we’ll place the “all” script (and a copy of jQuery) before the closing <body>
tag:
1 |
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script> |
2 |
<script src='https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.3.4/js/jquery.mmenu.min.all.min.js'></script> |
So, let’s start building the menu!
Setting Up the HTML
Let’s begin by understanding the structure of our page. Here’s the corresponding HTML code:
1 |
<div>
|
2 |
<header><!-- more content here --></header> |
3 |
<main><!-- more content here --></main> |
4 |
</div>
|
5 |
<nav id="menu"><!-- more content here --></nav> |
Notice that we place all the elements, except for the nav
element, within a containing div
.
We can use a different element as the container, but by doing so we’d then have to inform the plugin about this change via the relevant configuration property (i.e. the offCanvas.pageNodetype
property). Additionally, if possible, we should avoid declaring a number of CSS properties for the wrapper element. More specifically, the plugin recommends the following:
“This DIV is best off without a (min-/max-)width and height, padding, border and margin.”
The Markup
The next step is to take a closer look at the structure of the menu. The relevant HTML code looks like this:
1 |
<nav id="menu"> |
2 |
<ul>
|
3 |
<li>
|
4 |
<a href="#">About</a> |
5 |
<ul>
|
6 |
<li>
|
7 |
<a href="#">History<span>Click me</span></a> |
8 |
</li>
|
9 |
<li>
|
10 |
<a href="#">Vision</a> |
11 |
</li>
|
12 |
<li>
|
13 |
<a href="#">Team</a> |
14 |
</li>
|
15 |
</ul>
|
16 |
</li>
|
17 |
<li>
|
18 |
<a href="#">Services</a> |
19 |
</li>
|
20 |
<li>
|
21 |
<a href="#">Portfolio</a> |
22 |
</li>
|
23 |
<li>
|
24 |
<a href="#">Clients</a> |
25 |
</li>
|
26 |
<!-- more list items here -->
|
27 |
</ul>
|
28 |
</nav>
|
Here we’ve used some straightforward HTML code to build our menu. Unordered lists, with nested lists and links. The plugin doesn’t expect specific markup; happily, we are able to use any markup we want.
We assign a unique identifier to the menu, which we’ll use later in order to instantiate the plugin. Then last but not least, we hide it until all the styles have been successfully applied. This step is important because, by adding the following CSS code, we prevent a jarring FOUC:
1 |
nav { |
2 |
display: none; |
3 |
}
|
Now that we’ve prepared our page, it’s time to initialize the menu!
Firing the Plugin
Before showing how we can fire the plugin, let’s first cache a few of our selectors:
1 |
var $menu = $('#menu'); |
2 |
var $btnMenu = $('.btn-menu'); |
3 |
var $img = $('img'); |
Now we initialize it by using the code below:
1 |
$menu.mmenu({ // configuration settings here }); |
We can customize the default appearance and the functionality of our menu through CSS and the available configuration settings. We’ll see some examples of this in a moment.
Furthermore, we have the option to open and close the menu either automatically or manually. In our case, we’ll show the menu when the element with the btn
-menu
class is clicked. To achieve this functionality, we’ll take advantage of the available API. Here’s the required code:
1 |
var api = $menu.data("mmenu"); |
2 |
|
3 |
$btnMenu.click(function() { |
4 |
api.open(); |
5 |
});
|
In contrast, we’ll choose to hide the menu automatically. This is the default behavior; triggered when we click on any part of the page, except for the part that belongs to the menu.
Before we move on, there’s one more thing that I should mention. If we try to open a submenu by clicking on the target menu item (a
element), this item will not be entirely clickable. Specifically, the submenu will open only when we click on the right part of that menu item (see the live example to understand this behavior). To make the entire menu item clickable, we have to add the following line of code:
1 |
$menu.find( ".mm-next" ).addClass("mm-fullsubopen"); |
Changing the Off-Canvas Image
In this section, the goal is to show a different navigation icon depending on the state of our menu. The screenshot below visualizes what we want to achieve:



To make that happen, we’ll work with the opening
and closing
events. You can find the documentation of those events in the page which is related to the "offCanvas" add-on. Here’s the snippet we use to change the icons:
1 |
api.bind('opening', function() { |
2 |
$img.attr('src', 'arrows_remove.svg'); |
3 |
});
|
4 |
api.bind('closing', function() { |
5 |
$img.attr('src', 'arrows_hamburger.svg'); |
6 |
});
|
Beyond the events above, there are also a few others to play with (e.g. the opened
and closed
events) which you might find useful for your own projects.
Changing the Default Width
In order to change the predefined width of the menu, we can use either CSS or Sass (by modifying the source files). By default, its min-width
and max-width
property values are equal to 140px
and 440px
respectively. In our demo, let’s see how we can change the initial max-width
property value through CSS. Below are the CSS rules that need to be overridden:
1 |
.mm-menu { |
2 |
max-width: 350px; |
3 |
}
|
4 |
|
5 |
/**
|
6 |
* add more vendor prefixes
|
7 |
* depending on the browsers you're targeting
|
8 |
*/
|
9 |
|
10 |
@media all and (min-width: 550px) { |
11 |
html.mm-opening .mm-slideout { |
12 |
transform: translate(350px, 0); |
13 |
}
|
14 |
}
|
15 |
|
16 |
/**
|
17 |
* override this rule
|
18 |
* in case you're building a right menu
|
19 |
*/
|
20 |
|
21 |
@media all and (min-width: 550px) { |
22 |
html.mm-right.mm-opening .mm-slideout { |
23 |
transform: translate(-350px, 0); |
24 |
}
|
25 |
}
|
Additional CSS Changes
At this point, we’ll continue customizing the appearance of the menu. Again, we’ll edit the Sass source file to modify the styles according to our needs. Take a look at the rules that we’ll override below (for simplicity I have omitted the values of the Sass variables):
1 |
.mm-menu { |
2 |
background: darken($main-color, 10%); |
3 |
}
|
4 |
|
5 |
.mm-listview > li > a { |
6 |
color: $text-color; |
7 |
padding: 20px; |
8 |
}
|
9 |
|
10 |
.mm-listview > li > a:hover, |
11 |
.mm-listview .mm-next.mm-fullsubopen:hover + a { |
12 |
color: $highlight-color; |
13 |
}
|
14 |
|
15 |
.mm-listview > li > a:hover span { |
16 |
color: $text-color; |
17 |
}
|
18 |
|
19 |
.mm-menu .mm-listview > li.mm-selected > a:not(.mm-next) { |
20 |
background: transparent url(arrows_check.svg) no-repeat center right 10px; |
21 |
background-size: 30px 30px; |
22 |
text-decoration: line-through; |
23 |
}
|
Now consider the very last rule. Each time we click on a menu item, it receives the mm-selected
class, so we can use that selector to style it. But we only want to style the very last item in a selection process, so we’ll point to ones which don’t have the class of mm-next
.



Adding Extensions and Add-ons
In a previous section, we saw how we initialize the plugin. Now, let’s extend its behavior and functionality by overriding the default configuration options.
First, we change the title that appears above the main panel.
Next, we include the “counters” and the “off-canvas” add-ons. This last add-on allows us to change the position of the menu relative to the page.
Finally, we add three extensions. Check out the final initialization code below:
1 |
$menu.mmenu({ |
2 |
counters: true, |
3 |
navbar: { |
4 |
title: "Menu Content" |
5 |
},
|
6 |
extensions: ["pageshadow", "effect-zoom-menu", "effect-zoom-panels"], |
7 |
offCanvas: { |
8 |
position : "right", |
9 |
zposition : "back" |
10 |
}
|
11 |
});
|
Conclusion
In this tutorial, we went through the process of creating an off-canvas menu using the jQuery.mmenu plugin. As a next step, dig into the complete source for our demo on CodePen. Then, I suggest you jump into jQuery.mmenu’s official page and look at the various interactive examples that are available. Show us your examples in the comments!
If you're looking for a quick solution, don't forget that Envato Market has a collection of different CSS or JavaScript menus and navigation widgets. It's a good starting point for ideas and examples.