How to Build a Sliding Menu Using ReactJS and LESS CSS

Published Feb 19, 2015Last updated Feb 15, 2017
How to Build a Sliding Menu Using ReactJS and LESS CSS

I'd like to talk about how to create a sliding menu control using ReactJS and LESS CSS. The basic idea is that I want a menu to slide in from either the left or the right side of the screen based on some external page action. If you're the kind of person who wants to see the big picture instead of having a step by step tutorial laid out for you, I've put together a demo page, which you can see here. The menu itself will be a React JS class which takes just one argument: alignment, which determines whether the menu slides in from the left or right side of the screen.

I'm going to split the article up into two sections. First, I'll go over the React classes that we'll be using to do the rendering of the menu and the menu items, and then we'll discuss the LESS CSS I'm using to provide the fancy slide in and out animations.

React

There are three classes used to render the menus: App, Menu and MenuItem.

App

var App = React.createClass({
  showLeft: function() {
    this.refs.left.show();
  },

  showRight: function() {
    this.refs.right.show();
  },

  render: function() {
    return <div>
      <button onClick={this.showLeft}>Show Left Menu!</button>
      <button onClick={this.showRight}>Show Right Menu!</button>

      <Menu ref="left" alignment="left">
        <MenuItem hash="first-page">First Page</MenuItem>
        <MenuItem hash="second-page">Second Page</MenuItem>
        <MenuItem hash="third-page">Third Page</MenuItem>
      </Menu>

      <Menu ref="right" alignment="right">
        <MenuItem hash="first-page">First Page</MenuItem>
        <MenuItem hash="second-page">Second Page</MenuItem>
        <MenuItem hash="third-page">Third Page</MenuItem>
      </Menu>
    </div>;
  }
});

Here, we're adding two Menus to the app: one to slide in from the left, and another to slide in from the right. This behaviour is specified using the alignment prop on the Menu class declaration. We're also setting the refs of each Menu so that the button event handlers can call the respective show methods to have them slide in.

Inside the Menus, we've got instances of the MenuItem class, which are just menu entries that the user can click on to perform some action. In this case, the action is navigating to a particular hash, which is specified (unsurprisingly) using the hash prop on the class declaration.

var Menu = React.createClass({
  getInitialState: function() {
    return {
      visible: false	
    };
  },

  show: function() {
    this.setState({ visible: true });
    document.addEventListener("click", this.hide.bind(this));
  },

  hide: function() {
    document.removeEventListener("click", this.hide.bind(this));
    this.setState({ visible: false });
  },

  render: function() {
    return <div className="menu">
      <div className={(this.state.visible ? "visible " : "") + this.props.alignment}>{this.props.children}</div>
    </div>;
  }
});

The Menu class is responsible for two things: rendering the actual menu, and toggling the visibility of the menu based on calls to the show and hide methods. The getInitialState method indicates that the menu is hidden by default. The show method sets the visibility to true, while at the same time hooking up an event handler to hide the menu when the user clicks anywhere on the document. The hide method hides the menu and removes the aforementioned document click handler.

The render method spits out two divs, the inner of which contains an inline conditional to set the visible CSS class based on the accompanying state variable. It also sets a class based on the alignment prop, which will be either "left" or "right".

The inner contents of the Menu are being rendered from the children prop, which is a special prop that represents the inner content of the rendered HTML tag in the parent. In our case, this will be a bunch of MenuItem instances.

var MenuItem = React.createClass({
  navigate: function(hash) {
    window.location.hash = hash;
  },

  render: function() {
    return <div className="menu-item" onClick={this.navigate.bind(this, this.props.hash)}>{this.props.children}</div>;
  }
});

The MenuItem class is responsible for two things: rendering the item itself, and handling a click action. The first is accomplished in the render method, which builds just a simple div containing the menu-item CSS class and an on click handler, which calls the navigate method with the hash given at construction.

The text of the menu item is given via the children prop and as such is set when adding the MenuItem to the page. In this case, I'm using the completely uninspired "First Page" etc. nomenclature.

CSS

.menu {
  display:block;

  @menu-width:250px;

  >div {
    position:absolute;
    z-index:2;
    top:0;
    width:@menu-width; 
    height:100%; 
    .border-box; 
    .transition(-webkit-transform ease 250ms); 
    .transition(transform ease 250ms);

    &.left {
      background:#273D7A;
      left:@menu-width*-1;
    }

    &.visible.left {
      .transform(translate3d(@menu-width, 0, 0));
    }

    &.right {
      background:#6B1919;
      right:@menu-width*-1;
    }

    &.visible.right {
      .transform(translate3d(@menu-width*-1, 0, 0));
    }

    >.menu-item {
      float:left;
      width:100%;
      margin:0;
      padding:10px 15px;
      border-bottom:solid 1px #555;
      cursor:pointer;
      .border-box;
      color:#B0B0B0;

      &:hover {
        color:#F0F0F0;
      }
    }
  }
}

Note: There are various LESS CSS mixins I'm using in the code above to abstract away annoying vendor prefixes. I've left them out, as they're pretty verbose, but if you're interested in what those mixins look like, take a look at the source of the demo page.

The bulk of the CSS is used for positioning the left and right menus off screen, and then to animate them as they're shown. I'm using menu-width to set the max size of the menu, which helps with positioning so that the menus are just out of sight when hidden.

On the menu class definition, I've set the transition property (or mixin, here) twice to allow for vendor prefixes. I wasn't able to abstract this away completely into a mixin, unfortunately.

When the menu has the visible class attached to it, a transform gets added to the div, which slides it to the left or right depending on the alignment.

Conclusion

That's it! I hope this has taught you something as you've read through this. If you'd like to see these menus in action, you can check out the demo page, which adds both a left and a right menu to the page. Thanks for reading!

Discover and read more posts from Chris Harrington
get started
Enjoy this post?

Leave a like and comment for Chris

3
6
6Replies
Mushi@Q
4 months ago

Hey Chris do you have a repo for this project

Voon Ming Hann
6 months ago

Didn’t know you can access’s component function through ref!

Victor Leung
2 years ago

You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call.

seo yoochan
a year ago

without binding hide to this, this.setState() doesn’t work.

Laian007
a year ago

Hello, you found solution for remove this error ?
And how you can do if we click on the link from sidebar for dont close sidebar?

Best regards,

Show more replies

Get curated posts in your inbox

Read more posts to become a better developer