Pushy is a responsive off-canvas navigation menu using CSS transforms & transitions.

  • By Chris Yee
  • Last update: Dec 22, 2022
  • Comments: 17


Pushy is a responsive off-canvas navigation menu using CSS transforms & transitions. This project was inspired by the off-canvas navigation menu seen on Medium.

Pushy has been implemented on many sites, check them out! Feel free to let me know if you use Pushy in one of your websites.

Pushy has been featured on the Treehouse Show and in a book!

View Demo | Sites using Pushy


  • Uses CSS transforms & transitions.
  • Smooth performance on mobile devices.
  • jQuery animation fallback for IE 7 - 9.
  • Menu closes when a link is selected.
  • Menu closes when the site overlay is selected.
  • Auto-collapsible submenus.
  • Left or right menu position.
  • It's responsive!



Download the latest release, this includes everything you need to get Pushy running on your site.

  1. Add the stylesheet (pushy.css) in your head and the JS (pushy.min.js) file in your footer.

  2. If you are using submenus, then you'll need to add the arrow.svg file into your img directory (optional).

  3. Insert the following markup into your body.

<!-- Pushy Menu -->
<nav class="pushy pushy-left">
    <div class="pushy-content">
            <!-- Submenu -->
            <li class="pushy-submenu">
                    <li class="pushy-link"><a href="#">Item 1</a></li>
                    <li class="pushy-link"><a href="#">Item 2</a></li>
                    <li class="pushy-link"><a href="#">Item 3</a></li>
            <li class="pushy-link"><a href="#">Item 1</a></li>
            <li class="pushy-link"><a href="#">Item 2</a></li>

<!-- Site Overlay -->
<div class="site-overlay"></div>

<!-- Your Content -->
<div id="container">
    <!-- Menu Button -->
    <button class="menu-btn">&#9776; Menu</button>


Pushy CSS and JS are compiled and minified using Grunt. You'll need Node and Grunt installed globally.

From the root directory run:

$ npm install
$ grunt

Now you can edit files in /scss/ and /js/, which will be compiled to /css/pushy.css and /js/pushy.min.js automatically.


Link directly to Pushy files on cdnjs.


If your are comfortable with command line, you can install Pushy as a NPM package:

npm install @cmyee/pushy


Menu Position

Use the .pushy-left or .pushy-right CSS class to specify the menu position.

<!-- Pushy will transition from the right -->
<nav class="pushy pushy-right">
    <div class="pushy-content">
            <li class="pushy-link"><a href="#">Item 1</a></li>
            <li class="pushy-link"><a href="#">Item 2</a></li>


Use the data-focus attribute to give focus to a link when the menu is opened. Ideally the first link of the menu should be focused.

This data attribute accepts a CSS selector.

<nav class="pushy pushy-left" data-focus="#home-link">
    <div class="pushy-content">
            <li id="home-page" class="pushy-link"><a href="#">Home</a></li>
            <li class="pushy-link"><a href="#">About Us</a></li>
            <li class="pushy-link"><a href="#">Contact</a></li>


Use the data-menu-btn-selector attribute to change the menu button CSS class for toggling the menu.

By default Pushy will use .menu-btn to toggle the menu.

This data attribute accepts a CSS selector.

Note: In v1.4.0 this attribute was renamed from data-menu-btn-class to data-menu-btn-selector

<!-- Pushy Menu -->
<nav class="pushy pushy-left" data-menu-btn-selector=".my-menu-btn">
	<!-- I've removed the inner markup for brevity -->

<!-- Menu Button-->
<button class="my-menu-btn">Menu</button>


Use the data-container-selector attribute to using a custom #container selector.

If you use a custom #container selector you'll need to update the necessary CSS in pushy.scss.

This data attribute accepts a CSS selector.

<nav class="pushy pushy-right" data-container-selector="#custom-container">


  • Use the .push CSS class on HTML elements outside of the #container.
<header class="push">
    <h1>This is a Heading</h1>
    <h2>This is a subheading</h2>

<!-- Your Content -->
<div id="container"></div>
  • If you are using SCSS, you can easily change the menu width by adjusting the $menu_width variable. The SCSS file will need to be compiled to CSS in order to see the change.
$menu_width: 400px;
  • Not using SCSS? You'll have to update the multiple values (or do a find a replace!) in the pushy.css file.
    width: 400px; /* Changed the width to 400px */

    transform: translate3d(-400px,0,0); /* Updated the values */
    /* Don't forget the vendor prefixes */

.pushy-open-left #container,
.pushy-open-left .push {
    transform: translate3d(400px, 0, 0); /* Updated the values */

.pushy-right {
    transform: translate3d(400px, 0, 0); /* Updated the values */
    /* Don't forget the vendor prefixes */

.pushy-open-right #container,
.pushy-open-right .push {
    transform: translate3d(-400px, 0, 0); /* Updated the values */
    /* Don't forget the vendor prefixes */
  • Only links with the CSS class of pushy-link will close the menu.
<nav class="pushy pushy-left">
    <div class="pushy-content">
            <!-- This link will close the menu -->
            <li class="pushy-link"><a href="#">Item 1</a></li>
            <!-- This link won't close the menu -->
            <li><a href="#">Item 2</a></li>
  • If you want to prevent scrolling of your site when Pushy is open just add overflow-x: hidden and height: 100% to both the html & body tags.
html, body{
    overflow-x: hidden;
    height: 100%;
    -webkit-overflow-scrolling: touch;

Browser Compatibility

Desktop Mobile
IE 9-11 Chrome (Android)
MS Edge Safari (iOS)
Safari (Mac)

Sites using Pushy

Pushy has been implemented on many sites in the wild, check them out!

To add your site, tweet to me @cmyee.




  • 1

    Menu Length Issues

    I love this menu, however, I am experiencing the following issues when the length of the menu is longer than the page:

    1. I am unable to scroll down to view the rest of the menu on the desktop and mobile. It would be great if there are 2 separate vertical scrollbars, one for the menu and the other for the page content.
    2. When I resize the length of the browser while the menu is open, the menu's background color disappears.



  • 2

    Feature: Allow nested submenus

    This PR updates pushy to allow nested submenus.

    Updates include:

    • Add check for nested submenus
    • Stop propagation to help manage nested submenus
    • Add preventDefault() to allow submenu open/close links to function only as such
    • Add main entry to package.json to allow install via npm install github:mygithubuser/myproject

    Closes #90

  • 3

    Can't see navigation styling in desktop browser

    As the title says, I don't see any styling on the side navigation (.pushy .pushy-left) on my desktop browser (it just appears as blank). However, on my phone I can see the styling. This is what I'm seeing on the demo too, at http://www.christopheryee.ca/pushy/.

    It doesn't seem to be a media query hiding it because when I resize my browser to a mobile size this still happens.

    Is this default behavior? Can I change it? Makes development on a desktop browser hard. Thanks.

  • 4

    Double Menus

    I would love to be able to have menus sliding in from both sides or to be able to choose the direction the menu comes in from. Great plugin other than that.

  • 5

    Visible menu when at desktop size

    This is exactly what I'm after, however would it be possible to have the menu visible whilst at full desktop size? Then once you start to scale down the browser size (tablets/mobile) the menu disappears and the menu button appears like it is at current?

    I'm sure I could hack this together with Bootstrap or something, but I'd like to stay away from something like that.

    Any solutions?

  • 6

    Browser/Device Compatibility

    I'm noticing that this does not work in older Android devices like the Galaxy Tab and S2, for instance. I know, I know, upgrade, dammit! Haha. I agree. However, if that is not an option, can someone perhaps point me in the direction of getting this to work on these devices?

    I'm pretty sure it has to do with translate3d not being supported.

    Thank for any and all assistance.

  • 7

    Is there a way to fire multiple Pushy sections?

    Love the plugin and using it on a new site for the nav but was wondering if there's a way to add another off canvas element for a contact form and have that slide in on click separate from the navigation?

  • 8

    Pushy doesn`t work with wordpress

    I am tried to combine together wordpress and pushy, but its doesn`t work. Pushy.js included in wordpress, i use this code:

    wp_enqueue_script( 'wp-jquery', get_template_directory_uri() . '/libs/jquery/dist/jquery.min.js' );
    wp_enqueue_script( 'wp-pushy', get_template_directory_uri() . '/libs/pushy/js/pushy.js' );

    Styles are included and work well, but js doesnt work. In the source code pushy.js is displayed.

  • 9

    Overlapping Text

    Maybe it's my implementation but there seems to be overlapping of text.

    Using the example provided, if you put about 25 elements under the first drop down menu, when the drop down menu is expanded, the links of 25 menu elements/links cover over the text of the other links.

  • 10

    Can we have sub-submenus?

    Is it possible to have a sub-submenu? Below is a markup example:

      <nav class="pushy pushy-right">
          <li class="pushy-link">
            <a href="#">Item 1</a>
          <li class="pushy-submenu">
            <a href="#">Item 2 &gt;</a>
              <li class="pushy-link"><a href="#">sub item 1</a></li>
              <li class="pushy-submenu">
                <a href="#">sub item 2 &gt;</a>
                  <li class="pushy-link"><a href="#">sub sub item 1</a></li>
                  <li class="pushy-link"><a href="#">sub sub item 2</a></li>
                  <li class="pushy-link"><a href="#">sub sub item 3</a></li>
              <li class="pushy-link"><a href="#">sub item 2</a></li>
          <li class="pushy-link">
            <a href="#">Item 3</a>

    It wasn't clear to me if this only supported one level of submenus, or if I could have a nested submenu within a submenu.


  • 11

    Mobile Safari Back Button Caching


    I noticed an issue with Pushy and iOS Safari. If you open a link from the pushy menu in the same window then return to the previous page, the menu remains open. Unfortunately, to close it, you need to click the menu button to activate the site overlay then click the site overlay. It's pretty annoying. I'm not sure if this is a good fix for everybody, but I found a fix on Stack Overflow.

    // for jQuery
    $(window).bind("pageshow", function(event) {
        if (event.originalEvent.persisted) {window.location.reload();}
    // for regular JS
    window.onpageshow = function(event) {
        if (event.persisted) {

    Note: this won't break the back button functionality.

    Thanks, Steve

  • 12

    Multiple Pushy in one page

    Hello, I tried to setup multiple pushy in one page with different button selector (data-menu-btn-selector) but not working, do you have any example or demo about it? or maybe pushy doesn't support it?

  • 13

    Allow Multiple Pushy Menus with Different Buttons

    We've made some changes to enable using multiple buttons to trigger multiple different menus.

    Added Classes:

    wrp-pushy-trigger: to wrap the [menu-btn] inside it and to define the new data attributes

    Added Data Attributes:

    data-pushy-target: define the target menu unique class. data-pushy-body-class: add some unique classes to the body selector.


    <nav class="pushy pushy-left pushy-for-button-one">
        <div class="pushy-content">
    <nav class="pushy pushy-right pushy-for-button-two">
        <div class="pushy-content">
    <div class="wrp-pushy-trigger" data-pushy-target=".pushy-for-button-one" data-pushy-body-class="pushy-sidemenu-one another-class-one">
        <button class="menu-btn">Menu 1</button>
    <div class="wrp-pushy-trigger" data-pushy-target=".pushy-for-button-two" data-pushy-body-class="pushy-sidemenu-two another-class-two">
        <button href="#" class="menu-btn">Menu 2</button>
  • 14

    Desktop: Close '.pushy ul ul ' when clicking away from element

    I would like to see two methods of closing desktop submenu: Click .pushy button again OR click anywhere else on the HTML document.

    Similarly, in mobile view, after exposing nav.pushy, tapping button.menu-btn again should indeed hide nav.pushy but should also add .pushy-submenu-closed class to li.pushy-submenu.

    Thank you.

  • 15

    iOS Mobile Container Scrolling Bug

    On Mobile only on iOS devices, the site overlay fixed div does not block the scrolling of the container. The result is that the menu (if longer than the device viewport height) cannot scroll properly, and the page itself scrolls instead. This is a bug on the OS side I think...

    You can try your demo site on an iPad or iPhone, the container page keeps scrolling even after the menu is opened where as android it blocks the touch event. A quick but nasty solution I found was here.

    So for example, on your demo site I run code like: $('.site-overlay').on('touchmove', function(e){ e.preventDefault(); }); and then it works properly. Not saying it is the proper solution, but if you have any ideas let me know.


  • 16

    Tap status bar to scroll to top in Safari doesn't work

    On most websites when viewing on Safari on iOS 10.3.1, as you scroll down a page the Safari status URL reduces in height and when you double tap it, it scrolls to the top of the page.

    However, when using Pushy on a site, this feature no longer works. I think it might be something to do with the -webkit-overflow-scrolling:touch; CSS property. As explained here - http://stackoverflow.com/questions/14868053/webkit-overflow-scrollingtouch-and-tap-status-bar-to-scroll-to-top

    Can this be fixed?

  • 17

    Preventing scroll causes focus to top of page

    Using the css class that prevents the body from scrolling while pushy is open causes the page to focus at the top, as if a blank anchor tag (#) were clicked.

    Cannot figure out how to prevent scrolling but let the page remain in its natural position.