Multi-Level Push Menu

An experimental push menu with multi-level functionality that allows endless nesting of navigation elements.

From our sponsor: Try Mailchimp today.

Today we want to share another menu experiment with you. For sure you are familiar with the off-canvas navigation on mobile apps and the implementations for responsive websites like the one by David Bushell. We tried to explore the possibility of creating a nested multi-level menu, something that could be quite useful for menus with lots of content (like navigations of online stores). The result is a “push” menu that can (theoretically) contain infinite nested sub-menus. When opening a sub-level, the whole navigation pushes the content more, allowing a slice of the parent menu to be visible. Optionally, this slice can be visible or not, in which case the sub-menu will simply cover its parent.

Working with nested structures is quite tricky because when we, for example, move the parent then all children will of course move as well. So we are using a couple of tricks that will maintain the right 3D translates for the sub-menus and their children. The main idea is to increment the value for the translate so that we guarantee that the sub-levels are not shown once we push everything a bit more for showing the slices of the parents. This is of course not necessary in the case where the sub-menu is covering the parent menu.

Please note that we are using 3D Transforms which only work in modern browsers. You will find a fallback example for non-supporting browsers in the end of the component.css file where we simply show the first level menu. The same we do for the no JS case.

We are using the following nested structure for the menu:

<!-- mp-menu -->
<nav id="mp-menu" class="mp-menu">
	<div class="mp-level">
		<h2 class="icon icon-world">All Categories</h2>
			<li class="icon icon-arrow-left">
				<a class="icon icon-display" href="#">Devices</a>
				<div class="mp-level">
					<h2 class="icon icon-display">Devices</h2>
						<li class="icon icon-arrow-left">
							<a class="icon icon-phone" href="#">Mobile Phones</a>

							<div class="mp-level">
								<h2>Mobile Phones</h2>
									<li><a href="#">Super Smart Phone</a></li>
									<li><a href="#">Thin Magic Mobile</a></li>
									<li><a href="#">Performance Crusher</a></li>
									<li><a href="#">Futuristic Experience</a></li>

						<li class="icon icon-arrow-left">
							<!-- ... -->
						<li class="icon icon-arrow-left">
							<!-- ... -->
			<li><!-- ... --></li>
			<!-- ... -->
<!-- /mp-menu -->

…where each level is wrapped into a division with the class mp-level.

Normally, we would have used fixed positioning for a menu of this kind but since there is quite an peculiar “problem” with that (transforms will make it behave like an absolute positioned element), we’ll have to use absolute positioning which will leave us with some unwanted behavior of the site (scrolling of menu and dependence of document height). So we’ve used a little trick to avoid the menu being scrollable or to be cut off if the site’s content is too short by using the following page structure:

<div class="container">
	<!-- Push Wrapper -->
	<div class="mp-pusher" id="mp-pusher">

		<!-- mp-menu -->
		<nav id="mp-menu" class="mp-menu">
			<!-- ... -->
		<!-- /mp-menu -->

		<div class="scroller"><!-- this is for emulating position fixed of the nav -->
			<div class="scroller-inner">
				<!-- site content goes here -->
			</div><!-- /scroller-inner -->
		</div><!-- /scroller -->

	</div><!-- /pusher -->
</div><!-- /container -->

Where we set the following styles for the elements:

.scroller {
	height: 100%;

.scroller {
	overflow-y: scroll;

.scroller-inner {
	position: relative;

.container {
	position: relative;
	overflow: hidden;
	background: #34495e;

This will allow the content to be scrolled when the menu is closed and it will also make the menu being 100% of the window height. Basically, we are emulating what fixed positioning would do here.

This is how the plugin can be called:

new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ) );
Or, if the submenus should cover the previous levels: 
new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ), {
	type : 'cover'
} );

For the demos we are using the beautiful Linicons iconfont by Sergey Shmidt created with the help of the IcoMoon app.

We hope you enjoy this menu and find it useful.

Tagged with:

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 261

Comments are closed.
  1. I found the solution to my problem where menu was showing open on IOS when hitting the browser back button.
    There might better solution to implement in the plugin js file itself, but my js knowledge is limited.

    I simply use jquery removeClass to remove the “mp-pushed” and “mp-level-open” class as well as changing the style attribute to “-webkit-transform: translate3d(0, 0, 0)”

    jQuery('.my_link').click(function(){ jQuery('#mp-pusher').removeClass('mp-pushed'); jQuery('.mp-level').removeClass('mp-level-open'); jQuery('#mp-pusher').attr('style','-webkit-transform: translate3d(0, 0, 0)'); });

    So when you click/tap a link, you see the menu closing using the animation before loading the requested page.


  2. Hi all!

    i’ve question:

    how can i activate swipe effect in all smartphone mobile screen?

    Not only with the “box menu” but the effect start with swipe in all smartphone screen.

    I need the first version to smartphone mobile, and i tested it on Google Chrome (Android Kitkat). And it’s all ok, but doesn’t work the swipe effect.

    Thank you!

    • Well, I was searching comments for some other problem regarding this push menu… but found your post as the latest in comments..

      For sliding event you could check on the jQuery MOBILE Events:

      So when then slide happens, you could add a .click function to it as a function process…. I’m not good at jquery or javascript, but this was just a general idea I thought of when reading your comment/question.

      Do let me know if you succeed in it, as I could use the code for my project as well !!

  3. There appears to be issues with this package and the version of chrome, see It seems that on some versions of chrome Modernizr returns a false negative. On other versions all is well. In particular on Chrome Version 28.0.1500.71 (I believe this is the current version) the package does not work.

    I’d like to be able to use the package and am willing to help develop a fix.

  4. Is there a simple way to make it so that the overlap is shown on the left side instead of the right?

    • Yes, there is!
      Just switch all transforms from
      transform: translate3d(-100%, 0, 0);
      transform: translate3d(+100%, 0, 0);
      in the CSS-Files.

      In the JS-file switch the signs in the CSS-transitions as well
      In fact replace line 185 with
      this._setTransform( 'translate3d(-' + translateVal + 'px,0,0)' );
      and line 194 with
      this._setTransform( 'translate3d(+100%,0,0) translate3d(' + levelFactor + 'px,0,0)', levelEl );
      and line 221 with
      this._setTransform( 'translate3d(-' + translateVal + 'px,0,0)' );

      This should do the trick.

    • Sorry I Forgot some left vs. right CSS-Values.
      .pusher { /*left: 0;*/ right: 0; } .mp-level { /*left: 0;*/ right: 0; } .mp-menu { /*left: 0;*/ right: 0; }

  5. I really like this effect and plan to make use of it, so thank you for creating and sharing it with us.

    It’s too bad the behavior for browsers that don’t support transforms is pretty much an afterthought, though. I’d like to see a bit more of a progressive enhancement approach, and in this case I think it would be fairly easy to reveal all the menu levels with absolute positioning as a fallback with modernizr classes to activate it.

    Sounds like I just created a project for myself ๐Ÿ™‚

    • Did you work something out? ๐Ÿ™‚ I’m working on implementing this in IE8+ and would like to hear your experiences.

  6. Hi, I’ve tried to change it to slide from right to left without success.
    Any quick tricks?

    Please help.

  7. If I want the menu first level always open? I tried to change translate 3d to 0 in menu-level class, but it don’t worked fine.

    • Hi Dixon,

      Please help me out when i use this code, menu is disabled (functioning but am not able to see menu) please help me to fix this ๐Ÿ™

  8. Hello all,

    Thanks for the awesome piece of coding Mary Lou. Not to beat a dead horse, but I have seen many people asking how to make the menu slide in from the RIGHT. Any chance you would give us that modification or maybe a hint? (I will dance at your wedding & I have a few moves)

    I assume we need to change the CSS positioning as well as the transformations being set in the mlpushmenu.js? Correct?

    • I too need this (awesome) menu showing up on the right for a project of mine but it doesn’t seem as though anyone has worked out how to do it. ๐Ÿ™

      Would really appreciate some help on this or if anyone has worked out how to do this, to share their solution.

  9. How can I use this jquery plugin for a wordpress website? Is there any way to use this on wordpress?


    • You can use this on wordpress. It took me a couple of hours but you need to adjust the wordpress nav structure very slightly.

  10. Hi Mary

    I use your MULTI-LEVEL PUSH MENU I clicked your menu item but it doesnt work. How can I work click item ?

  11. I think it’s safe to say there is no support from the team at tympanus for this menu anymore ๐Ÿ™

  12. Hi.

    Am using this code for mobile site but when i use “-webkit-overflow-scrolling: touch;” the menu is disabled ๐Ÿ™ Can u please help me out Please..

  13. To show MENU

    Only comment in mlpushmenu.js:

    if( this.level === 1 ) {
    //classie.add( this.wrapper, ‘mp-pushed’ ); <——
    // = true;

    And use the next code

    mainMenu = new mlPushMenu( document.getElementById( ‘mp-menu’ ), document.getElementById( ‘trigger’ ), {
    type : ‘overlap’});

    • By the way, I needed to make the menu to be opened when the document is loaded, but keeping the option of closing it too if I wanted, so what I did is:

      Comment in mlpushmenu.js:
      if( this.level === 1 ) { classie.add( this.wrapper, โ€˜mp-pushedโ€™ ); // = true; <โ€”โ€” }

      And keep in the html the code provided by Daniel just the way he did it:

      mainMenu = new mlPushMenu( document.getElementById( โ€˜mp-menuโ€™ ), document.getElementById( โ€˜triggerโ€™ ), { type : โ€˜overlapโ€™}); mainMenu._openMenu();

  14. I’ve used this plugin to one of my websites and I’m loading pages with ajax. So after load a page on complete I wanted to close the menu. So on my function I did this:

    At the start of my function:
    side_menu = new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ) );

    Then inside my complete
    I called the function as : side_menu._resetMenu()

    You can also close the menu with $('body').trigger('click') but I think is not that right.

    Hope this helps to someone.

    Thanks ML

    • I can’t make it work ๐Ÿ™ could you please paste your code? It would be very appreciated…

  15. Hello, this is a great piece of work.

    Maybe I’ve missed some previous comments (so probably the following issue has been discussed already): it is possible to make scrollable each menu levels? If I have a menu level with many elements that extend below the fold, it is possible to get a scrollbar (desktop) or finger swipe on mobile?


  16. Oooops. I think my first reply had a hiccup. So let’s try again.
    Always amazing stuff to see here. Everything works fine so far for me, but I’m really not good at coding and what I would like to achieve is a further dynamic page load for the content-wrapper. It would be great if not the whole page reloads.
    I try some tutorials from css-tricks but couldn’t get it to work. Maybe you have a hint or a sample according to your code?!

    Any help is appreciated. Best. Sebastian.

  17. Hey i want to add this menu style to my project website, but when i merge code of my page what happens is the menu stays up and then my code’s desgin i want to put this menu in my page please help me with its CSS..

  18. Hello! I appreciate this wonderful menu. It is very well built ๐Ÿ˜‰

    I would just like to know if it was possible to make one more feature, which is for example a button that is in the body, and that when clicked redirects the menu for a part of it.

    Example: Clothes button that when clicked opens the menu tab on apparel.

    In the link below, is a project that you have found this functionality, but would like to possibly do the same in your menu because I’m using it;)

    Project Link Download:

    (ex: expandcollapse)

    Thank you very much.

    I expect a response from you ๐Ÿ˜‰

    Best Regards,

    Ivo Reis.

  19. OMG – what great code – I am having difficulty making the links in the menu work – do not know what is wrong – when I click the link it does nothing!

    Any directions?

  20. Hy Mary Lou ๐Ÿ˜‰

    Can you put one more demo (Demo 4) that has a button that when clicked, automatically opens the menu in a specific category?

    Example: “Button – Go to Devices / Televisions”

    Thank you very much.

  21. Hi

    I love what you do on this site, it is so engaging and inspirational. I wish I could show my site, but my work cannot be displayed. Quick question,
    I like the push menus and the interactions; I was wondering, if it is possible to hide the push menu upon scrolling. For instance if the push menu is exposed and then upon a scroll event, I want it to retract. Is this possible?

    Thank you,
    Sam Shoulders

  22. i loved the design, my question is it possible to fix the scrolll bar on the menu. because i am having huge number of items. Any body can help me?

  23. Just wondering if anyone knows how to move the menu to the other side of the screen so that it opens up on the right.
    I tried tinkering with it yesterday, but could only get as far as moving to the other side, and having it overlap… incorrectly. Any help would be appreciated.

  24. ISSUE:
    If you have more items in the menu then the height of your display you cant get to them … the menu cant scroll down!

  25. In this , the content get hided while showing the menu, Is it possible to shrink the content? In my project i need this adjustment.. guide me to do this “shrink the contents”

    • I found the solution:

      add new function:

      function closeMe(){ var container = document.getElementById( 'st-container' ); classie.remove( container, 'st-menu-open' ); };

      the call it in menu

      <li><a class="icon icon-star" href="#" onclick="closeMe();">Exit1</a></li> <!--formatted-->

  26. PROBLEM:

    For mobile users, (android or iOS) when you tap on a menu item that contains a submenu, whatever menu item that WOULD be directly ON TOP OF the parent item you just tapped is “tapped” and goes to that page. The only way to get it to not “self tap” the child item is by long pressing the parent item and then dragging your finger off the menu after the submenu slides in. Then you can tap any of the submenu items you want. Has anyone experienced this?

  27. Hello,

    I am trying to use this menu with jquerymobile, and i couldn’t trigger it when new page loaded, because it’s loads content with ajax.

    When i try to init it in pageinit function, it’s break. Any suggestions?

    $("#wrapper").live('pageinit',function() { new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ) ); });

  28. having problem while scrolling . in this , menu i have a huge list of data in menu. for example: Level-1 has 40 elements and Level-2 has 20 elements
    i am scrolling level-2(is top most level) and it has 20 elements means it scroll to the end after that it shows the elemnts of level-1(parent of level-2).
    How can i stop showing of the elements from level-1 while scrolling level-2

    • I have this same problem on landscape in mobile – I cannot scroll all the way to the bottom of the dropdown list.

  29. I found a bug. I have no clues how to fix it.
    Only on Firefox ( i havent tested IE)
    if you have a fixed element inside the mp-pusher (e.g. try to add a position:fixed to the codrop top bar ).
    this fixed element will disappear once you click on the trigger.
    Do you have any idea how to solve it?

  30. Love this. I would just very much see a version that does not depend on 3d transforms so it can be used in older browsers too. I know there has been made a jQuery plugin about Mary’s lovely menu ( which works in IE8. However, I would like to use 3d transforms in browsers that supports it and as a fallback I’d use the jQuery plugin. Unfortunately it’s not the exact same markup structure in the jQuery plugin which makes it difficult to use both Mary’s menu and the jQuery plugin. Has anyone got any experience with fallbacks to IE8+ using the one with 3d transforms and the jQuery plugin?

    Thanks in advance.

    • first change line 98 of mlpushmenu.js to:
      this.eventtype = ‘click’;

      (Windows phone IE doesn’t recognize ‘touchStart’)
      then in your css add:

      @-ms-viewport {
      width: auto;

      This fixes scrolling.

    • The fix by Matt doesn’t work. If i modify the line 98, the menu never appear when i it the buttonโ€ฆ

  31. I found a bug in iOS, if the page has a lot of content and is a very high page, when you touch the iOS bar to slide up to the top, it does not. Has anyone noticed this and have any solutions?

  32. Hi, what if I have a lot of items in the list so I need a scroll function in menu? Thanks ๐Ÿ™‚

    • Yep, my issue too. My lazy workaround is just to create more levels- split the categories up more….

  33. Getting this: Uncaught TypeError: Cannot read property 'querySelectorAll' of null mlpushmenu.js:89
    How can el be undefined?

  34. I have found this to be one of the best slider navs out there and I really appreciate all the work put in to this so thanks for sharing it! While using it I ran into a few bugs that I found solutions to so I want to share those with the community in case anyone else runs into them but haven’t found a solution here yet. I know, I probably should have read the previous comments first but here goes:

    iOS scrolling issues.
    I added these lines to my css
    .scroller {
    overflow-y: scroll;
    .scroller {
    -webkit-overflow-scrolling: touch;
    .scroller > * {
    -webkit-transform: translateZ(0px);
    This gives smooth scrolling to iOS while also fixing those blank areas you get while scrolling where you have to wait until you stop scrolling for the content to display.

    Windows Phone 8.0 clicking the button to open the nav didn’t work.
    in mlpushmenu.js change line 98 from:
    this.eventtype = mobilecheck() ? ‘touchstart’ : ‘click’;
    this.eventtype = ‘click’;
    (that browser doesn’t recognize ‘touchstart’ as an event. )

    Windows Phone 8.0 Scrolling didn’t work.
    in my css I added these lines:
    body, html, .scroller {
    -ms-overflow-style: none !important;
    @-ms-viewport {
    width: auto;

    remaining issues:
    IE 9 and below: the plugin doesn’t seem to work but at that point I would call it ‘progressive enhancement’ or ‘graceful degradation’ (your pick) and switch to a more simple navigation solution for those browsers.

    Hopefully this is helpful to someone.

  35. Hi, there, try to work with this multilevelpushmenu, but got two Problems, what, if the list of menu-items is too long for a site on a screen or a smartphone, but you don’t want to have a scrollbar? And on my smartphone the menu-icon to open the menu-levels often does not react (only whe I touched several times…) Has anyone got an idea?


  36. This is very nice, but there is one problem. Once there is the right push, the right area is not resized and any content that was previously close to the right edge vanishes.

    I want it to resize automatically… is that possible?

  37. Does anyone knows if the code was updated with the fixes? Or is it “bugged” since the beginning ?!
    I’m asking this because i really liked!