React-React sidebar 2.3: A sidebar component for React

icon
Latest Release: 2.3
  • Replace findDOMNode by ref callback (@BDav24)
  • Allow setting initial sidebar width (@BDav24)
Source code(tar.gz)
Source code(zip)

React Sidebar npm version Build Status

React Sidebar is a sidebar component for React 0.14+. It offers the following features:

  • The sidebar can slide over the main content or dock next to it.
  • Touch enabled: swipe to open and close the sidebar like on a native mobile app.
  • Easy to combine with media queries to show the sidebar only when there's enough screen-width (see example).
  • Works on both the left and right side.
  • Tiny size: <2.5kB gzipped
  • MIT license

See a demo here.

Touch specifics

The touch interaction of the React Sidebar mimics the interactions that are supported by Android apps that implement the material design spec:

  • When the sidebar is closed, dragging from the left side of the screen will have the right side of the sidebar follow your finger.
  • When the sidebar is open, sliding your finger over the screen will only affect the sidebar once your finger is over the sidebar.
  • On release, it will call onSetOpen prop if the distance the sidebar was dragged is more than the dragToggleDistance prop.

Note: The sidebar touch functionality doesn't work on IOS because of the "swipe-to-go-back" feature. Therefore the functionality has been disabled on IOS.

Installation

npm install react-sidebar

If you use TypeScript, typings are available on DefinitelyTyped and can be installed with:

npm install @types/react-sidebar

Getting started

By design, React Sidebar does not keep track of whether it is open or not. This has to be done by the parent component. This allows the parent component to make changes to the sidebar and main content based on the open/docked state. An example could be to hide the "show menu" button from the main content when the sidebar is docked.

Because React Sidebar can be toggled by dragging the sidebar into its open/closed position, you will have to pass in an onSetOpen method as a prop to allow the sidebar to control the open state in the parent.

The minimum React component to integrate React Sidebar looks like this:

import React from "react";
import Sidebar from "react-sidebar";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sidebarOpen: true
    };
    this.onSetSidebarOpen = this.onSetSidebarOpen.bind(this);
  }

  onSetSidebarOpen(open) {
    this.setState({ sidebarOpen: open });
  }

  render() {
    return (
      <Sidebar
        sidebar={<b>Sidebar content</b>}
        open={this.state.sidebarOpen}
        onSetOpen={this.onSetSidebarOpen}
        styles={{ sidebar: { background: "white" } }}
      >
        <button onClick={() => this.onSetSidebarOpen(true)}>
          Open sidebar
        </button>
      </Sidebar>
    );
  }
}

export default App;

Responsive sidebar

A common use case for a sidebar is to show it automatically when there is enough screen width available. This can be achieved using media queries via window.matchMedia. This again has to be integrated into the parent component so you can use the information to make changes to the sidebar and main content.

import React from "react";
import Sidebar from "react-sidebar";

const mql = window.matchMedia(`(min-width: 800px)`);

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sidebarDocked: mql.matches,
      sidebarOpen: false
    };

    this.mediaQueryChanged = this.mediaQueryChanged.bind(this);
    this.onSetSidebarOpen = this.onSetSidebarOpen.bind(this);
  }

  componentWillMount() {
    mql.addListener(this.mediaQueryChanged);
  }

  componentWillUnmount() {
    mql.removeListener(this.mediaQueryChanged);
  }

  onSetSidebarOpen(open) {
    this.setState({ sidebarOpen: open });
  }

  mediaQueryChanged() {
    this.setState({ sidebarDocked: mql.matches, sidebarOpen: false });
  }

  render() {
    return (
      <Sidebar
        sidebar={<b>Sidebar content</b>}
        open={this.state.sidebarOpen}
        docked={this.state.sidebarDocked}
        onSetOpen={this.onSetSidebarOpen}
      >
        <b>Main content</b>
      </Sidebar>
    );
  }
}

export default App;

Supported props

Property name Type Default Description
children Anything React can render n/a The main content
rootClassName string n/a Add a custom class to the root component
sidebarClassName string n/a Add a custom class to the sidebar
contentClassName string n/a Add a custom class to the content
overlayClassName string n/a Add a custom class to the overlay
defaultSidebarWidth number 0 Width in pixles of the sidebar on render. Use this to stop the sidebar from poping in after intial render. (Overrides transitions)
sidebar Anything React can render n/a The sidebar content
onSetOpen function n/a Callback called when the sidebar wants to change the open prop. Happens after sliding the sidebar and when the overlay is clicked when the sidebar is open.
docked boolean false If the sidebar should be always visible
open boolean false If the sidebar should be open
transitions boolean true If transitions should be enabled
touch boolean true If touch gestures should be enabled
touchHandleWidth number 20 Width in pixels you can start dragging from the edge when the sidebar is closed.
dragToggleDistance number 30 Distance the sidebar has to be dragged before it will open/close after it is released.
pullRight boolean false Place the sidebar on the right
shadow boolean true Enable/Disable sidebar shadow
styles object See below Inline styles. These styles are merged with the defaults and applied to the respective elements.
rootId string n/a Add an id to the root component
sidebarId string n/a Add an id to the sidebar
contentId string n/a Add an id to the content. The driving use case for adding an element id to content was to allow react-scroll to scroll the content area of the site using react-sidebar.
overlayId string n/a Add an an id to the overlay

Styles

Styles are passed as an object with 5 keys, root, sidebar, content, overlay and dragHandle, and merged to the following defaults:

{
  root: {
    position: "absolute",
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    overflow: "hidden"
  },
  sidebar: {
    zIndex: 2,
    position: "absolute",
    top: 0,
    bottom: 0,
    transition: "transform .3s ease-out",
    WebkitTransition: "-webkit-transform .3s ease-out",
    willChange: "transform",
    overflowY: "auto"
  },
  content: {
    position: "absolute",
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    overflowY: "auto",
    WebkitOverflowScrolling: "touch",
    transition: "left .3s ease-out, right .3s ease-out"
  },
  overlay: {
    zIndex: 1,
    position: "fixed",
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    opacity: 0,
    visibility: "hidden",
    transition: "opacity .3s ease-out, visibility .3s ease-out",
    backgroundColor: "rgba(0,0,0,.3)"
  },
  dragHandle: {
    zIndex: 1,
    position: "fixed",
    top: 0,
    bottom: 0
  }
};

Acknowledgements

My goal was to make a React Component that implements the material design spec for navigation drawers. My initial attempt was to improve hamburger-basement by arnemart but I quickly figured that I better start from scratch. Still, that project helped me a ton to get started.

Comments

  • Feature Request: Add Custom Event on Overlay
    Feature Request: Add Custom Event on Overlay

    Oct 2, 2019

    I want to show the overlay when in Desktop, but i can't reach him to add a OnClick custom event

    Reply
  • Failed prop type: The prop children is marked as required in Sidebar
    Failed prop type: The prop children is marked as required in Sidebar

    Oct 25, 2019

    Hi, I am getting this error. Should we add something for children? I dont see that u use it in the example.

    Warning: Failed prop type: The propchildrenis marked as required inSidebar, but its value isundefined. in Sidebar (created by Header) in Header (created by App) in div (created by App) in App (created by Route) in Route in ScrollToTop (created by Route) in Route (created by withRouter(ScrollToTop)) in withRouter(ScrollToTop) in Router (created by BrowserRouter) in BrowserRouter

    Reply
  • Can't render sidebar inside my split pane windows properly
    Can't render sidebar inside my split pane windows properly

    Oct 28, 2019

    I am using react and have a split pane window. Now I'd like to render the sidebar inside this pane window. I have sidebarStyle as following: image

    unfortunately it can not render properly as the height is always 0.

    if I change the above position from "absolute" to "relative". It renders, but the sidebar fills the entire pane. The size is wrong. image

    Here is my wrapper for the pane window image

    If I render sidebar outside the pane window, it works. Any suggestions are greatly appreciated.

    Reply
  • No label for version 3.0.2
    No label for version 3.0.2

    Nov 27, 2019

    Please add a Label for version 3.0.2. We need this to know which sources are used for version 3.0.2

    Reply
  • How to use with children that use flexbox (required by react-native)
    How to use with children that use flexbox (required by react-native)

    Jan 22, 2020

    Hello, I am doing an app with react-native which use flexbox for positioning elements.

    When I create the <SideBar />, the children <View /> use justifyContent: 'flex-end' to fix some content at the bottom of my view. (Like explained here: https://medium.com/react-native-training/position-element-at-the-bottom-of-the-screen-using-flexbox-in-react-native-a00b3790ca42)

    This is my SideBar and it break my layout:

    import React from 'react';
    import Sidebar from 'react-sidebar';
    
    const mql = window.matchMedia(`(min-width: 800px)`);
    
    class Navigator extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          docked: mql.matches,
          open: false
        };
    
        this.mediaQueryChanged = this.mediaQueryChanged.bind(this);
        this.toggleOpen = this.toggleOpen.bind(this);
        this.onSetOpen = this.onSetOpen.bind(this);
      }
    
      componentWillMount() {
        mql.addEventListener('change', this.mediaQueryChanged);
      }
    
      componentWillUnmount() {
        mql.removeEventListener('change', this.mediaQueryChanged);
      }
    
      onSetOpen(open) {
        this.setState({ open });
      }
    
      mediaQueryChanged() {
        this.setState({
          docked: mql.matches,
          open: false
        });
      }
    
      toggleOpen(ev) {
        this.setState({ open: !this.state.open });
    
        if (ev) {
          ev.preventDefault();
        }
      }
    
      render() {
        const {
          drawerContent: DrawerContent,
          children,
        } = this.props;
    
        const sidebarProps = {
          sidebar: <DrawerContent />,
          docked: this.state.docked,
          open: this.state.open,
          onSetOpen: this.onSetOpen
        };
    
        return (
          <Sidebar {...sidebarProps}>
            {children}
          </Sidebar>
        );
      }
    }
    

    How can I use the <SideBar /> without breaking the flex configuration of my layout?

    Reply
  • Keep Sidebar Content fixed
    Keep Sidebar Content fixed

    Mar 1, 2020

    Hello!

    I've been trying to let the Menu fixed when scrolling, but it just won't, any suggestions please?

     <Sidebar
            sidebar={
                <ul className="rooedaSidebar">
                    <Link element={Link} to="/">
                        <img src={LogoRooeda} alt='Rooeda Studio' className="sidebarLogoRooeda" />
                    </Link>
                    <li><Link element={Link} to="/">Studio</Link></li>
                    <li><Link element={Link} to="/">Instructores</Link></li>
                    <li><Link element={Link} to="/pickuppack">Packs</Link></li>
                    <li><Link element={Link} to="/">Calendario</Link></li>
                    <li><Link element={Link} to="/login">Iniciar sesión</Link></li>
                </ul>
            }
            open={this.state.sidebarOpen}
            onSetOpen={this.onSetSidebarOpen}
            shadow={false}
            styles={{ 
                root: { },
                sidebar: { 
                    background: "rgba(25,25,25, 0.70)", 
                    backdropFilter: "saturate(180%) blur(20px)",
                    webkitBackdropFilter: "saturate(180%) blur(20px)",
                    paddingTop: "15pt",
                    paddingLeft: "10pt",
                    paddingRight: "90pt",
                },
                content: { overflowY: 'auto' },
                overlay: {
                    backgroundColor: "rgba(25,25,25, 0.30)",
                    overflow: "hidden",
                }
            }}
            >
            <div onClick={() => this.onSetSidebarOpen(true)} className="burguerMenu">
                <Menu32 />
              </div>
          </Sidebar>
    

    Thanks in advance, R

    Reply
  • Printing Main Content
    Printing Main Content

    Dec 10, 2015

    So, when I go to print content that's in the main area, it's being truncated after on one page with a scrollbar visible. What's up with that?

    screenshot from 2015-12-10 12-01-10

    That's a screenshot of what I'm talking about. If I were to select the content (images) and do a "print selection", I get two pages of images, as opposed to one page (truncated) and a scrollbar. Any thoughts?

    Reply
  • Uncaught TypeError: Cannot read property 'mql' of undefined
    Uncaught TypeError: Cannot read property 'mql' of undefined

    May 25, 2016

    I am trying the example from the README where the sidebar responds to the browser width, and I get the following error when I resize my browser manually and cross over the threshold of 800px going in either direction:

    Uncaught TypeError: Cannot read property 'mql' of undefined

    Is this the expected behavior?

    Reply
  • Update README.md
    Update README.md

    Mar 9, 2018

    Fixing Responsive sidebar example' syntax error.

    Reply
  • Add `rootClassName` props
    Add `rootClassName` props

    May 28, 2016

    plz review

                                                                                                                                                                                                           
    Reply
  • Multiple Sidebar
    Multiple Sidebar

    Aug 31, 2016

    Hi,

    How can i have multiple sidebar .. in right and left side

    any possibility with this ??

    Reply
  • Add properties to set element Id.
    Add properties to set element Id.

    Aug 3, 2018

    Add properties to set Id of elements in Sidebar everywhere you can set class at moment. Add setting contentId in example. Add to do README.md documentation of properties.

    Reply