react-burger-menu and react-sidebar are both React components designed to create off-canvas side menus, commonly known as hamburger menus or slide-out drawers. While they solve the same visual problem, they approach it differently. react-burger-menu focuses on providing a variety of pre-built animation styles (like slide, push, overlay, and reveal) with a high degree of customization for the menu's behavior and appearance. It acts as a wrapper that manages the state of the menu (open/closed) and applies CSS transforms to your content. react-sidebar, on the other hand, is a more lightweight, unopinionated component that primarily handles the sliding mechanics of the sidebar itself. It expects the developer to manage the triggering logic and often requires more manual setup for the overlay and content shifting, offering a simpler API for standard slide-in effects without the extensive preset animations of its counterpart.
Building a responsive navigation drawer is a common requirement in modern web apps. While both react-burger-menu and react-sidebar solve this problem, they take very different approaches to architecture, animation, and developer control. Let's break down how they work under the hood.
react-burger-menu shines with its variety of built-in animation presets. You don't just get a slide-in menu; you get push, overlay, reveal, and scale effects out of the box. The library handles the complex CSS transforms required to move both the menu and the main content simultaneously.
// react-burger-menu: Using the 'push' animation preset
import { push as Menu } from 'react-burger-menu';
function App() {
return (
<Menu pageWrapId={"page-wrap"} outerContainerId={"outer-container"}>
<a href="/">Home</a>
<a href="/about">About</a>
</Menu>
);
}
react-sidebar focuses on a single, standard slide-in behavior. It does not offer multiple animation presets. If you need the main content to move when the sidebar opens, you must handle that logic yourself or rely on simple CSS classes. It is strictly for sliding the sidebar over or pushing content via manual intervention.
// react-sidebar: Basic slide-in implementation
import Sidebar from 'react-sidebar';
function App() {
const [sidebarOpen, setSidebarOpen] = React.useState(false);
const sidebarContent = (
<div>
<a href="/">Home</a>
<a href="/about">About</a>
</div>
);
return (
<Sidebar
sidebar={sidebarContent}
open={sidebarOpen}
onSetOpen={setSidebarOpen}
>
<button onClick={() => setSidebarOpen(!sidebarOpen)}>
Toggle Menu
</button>
<div>Main Content Here</div>
</Sidebar>
);
}
react-burger-menu manages its own internal state by default. It automatically creates a hamburger button for you. While you can control it via props (isOpen, onStateChange), the default usage is very quick because it renders the trigger button internally. You often need to wrap your entire app content in specific IDs (pageWrapId, outerContainerId) so the library knows what to animate.
// react-burger-menu: Requires specific container IDs for animation context
<div id="outer-container">
<Menu pageWrapId={"page-wrap"} outerContainerId={"outer-container"}>
<a id="home-link" className="menu-item" href="/">Home</a>
</Menu>
<main id="page-wrap">
{/* Your page content */}
</main>
</div>
react-sidebar is fully controlled. It does not render a trigger button. You must provide the open state and the onSetOpen handler. This gives you precise control over where the toggle button lives in your DOM, which is useful if your design system has a specific header component that shouldn't be wrapped by the menu library.
// react-sidebar: Fully controlled via props
const [isOpen, setIsOpen] = useState(false);
return (
<Sidebar
sidebar={...}
open={isOpen}
onSetOpen={setIsOpen}
>
{/* You decide where the button goes */}
<header>
<button onClick={() => setIsOpen(true)}>Menu</button>
</header>
<main>Content</main>
</Sidebar>
);
react-burger-menu automatically generates a semi-transparent overlay when the menu is open. It also handles locking the body scroll to prevent the background from moving while the menu is active. This is handled internally, saving you from writing extra logic.
// react-burger-menu: Overlay and scroll lock are automatic
// No extra code needed for overlay or preventing background scroll
<Menu>
<a href="/">Link</a>
</Menu>
react-sidebar also provides an overlay, but its behavior regarding scroll locking can sometimes require additional CSS or configuration depending on your layout. It renders the overlay as part of the component, but because it is less opinionated about the page structure, you might need to ensure your CSS handles the position: fixed context correctly on mobile devices.
// react-sidebar: Overlay is included, but layout context matters
<Sidebar sidebar={...} open={true} onSetOpen={() => {}}>
{/* Content */}
</Sidebar>
// Developer may need to add CSS to ensure body doesn't scroll
// if the sidebar doesn't capture all touch events effectively.
react-burger-menu uses a unique class naming convention (e.g., bm-menu, bm-item-list) for its internal elements. You target these classes in your CSS to change colors, widths, and fonts. Because it applies inline styles for animations, you sometimes have to use !important or specific selectors to override default behaviors.
/* react-burger-menu: Targeting internal classes */
.bm-menu {
background: #373a47;
width: 300px;
}
.bm-item-list a {
color: #d1d1d1;
}
react-sidebar allows you to pass style objects directly to the component props (styles={{ sidebar: {...}, overlay: {...} }}). This keeps your styling logic within your JavaScript files if you prefer that, though you can also use CSS classes. It feels more like a standard React component where you pass props to configure look and feel.
// react-sidebar: Passing style objects directly
<Sidebar
sidebar={...}
styles={{ sidebar: { background: '#fff', width: '250px' } }}
open={isOpen}
onSetOpen={setIsOpen}
/>
It is important to note that both packages have seen reduced maintenance activity in recent years. They rely on older React patterns (like class components and legacy lifecycle methods) rather than modern hooks-based architectures.
react-burger-menu is feature-rich but can feel heavy if you only need a simple drawer. Its reliance on specific DOM IDs (pageWrapId) can sometimes cause issues in complex nested layouts or when using Strict Mode in React 18.react-sidebar is simpler but lacks the polish of the former. It may require more polyfills or CSS fixes for modern mobile browsers.For new projects, consider if you truly need an external library. Modern CSS (using transform and transition) combined with a simple React state hook can often replicate these features with less bundle weight and better long-term maintainability.
// Modern Alternative: Custom Hook + CSS
function useDrawer() {
const [open, setOpen] = useState(false);
// Add logic to lock body scroll here
return { open, setOpen };
}
// Then use standard CSS transitions for the slide effect
<div className={`sidebar ${open ? 'open' : ''}`}>...</div>
| Feature | react-burger-menu | react-sidebar |
|---|---|---|
| Animations | Multiple presets (Push, Overlay, Reveal) | Basic Slide only |
| Trigger Button | Built-in (automatic) | Manual (you provide it) |
| State Management | Internal (with control props) | Fully Controlled (props only) |
| Styling Approach | CSS Classes (.bm-menu) | Style Objects or Classes |
| Setup Complexity | Medium (requires specific IDs) | Low (standard props) |
| Best Use Case | Complex animations, quick setup | Simple slide, custom triggers |
react-burger-menu is the choice for developers who want a visually impressive menu with minimal effort. If you need the content to "push" away or the menu to "reveal" from behind, this library handles the heavy lifting. It is great for prototypes or applications where the menu is a central design feature.
react-sidebar is for developers who want a no-frills, functional drawer. It respects your existing layout structure more than react-burger-menu because it doesn't force you to wrap your entire app in specific IDs. Choose this if you have a custom header component and just need a panel to slide in from the side.
Final Thought: Both tools solve the same problem but cater to different needs for control versus convenience. However, given the age of these libraries, always evaluate if a custom CSS/React solution might serve your project better in the long run, ensuring compatibility with the latest React features and reducing dependency bloat.
Choose react-burger-menu if you need a rich set of built-in animation styles (such as 'push', 'overlay', or 'reveal') and want a component that manages the entire menu lifecycle, including overlay handling and body scroll locking. It is ideal for projects where the sidebar interaction is complex or where you want to avoid writing custom CSS transitions for different menu behaviors. This package is best when you need a 'batteries-included' solution that works immediately with minimal configuration.
Choose react-sidebar if you prefer a lightweight, minimalistic approach and only need a basic slide-in effect without complex animations. It is suitable for developers who want full control over the trigger logic and overlay implementation, or those who need to integrate the sidebar into an existing layout system where react-burger-menu's automatic content shifting might interfere. Select this if you value a smaller API surface and are comfortable handling the surrounding UI state manually.
An off-canvas sidebar React component with a collection of effects and styles using CSS transitions and SVG path animations.
Using Redux? Check out redux-burger-menu for easy integration of react-burger-menu into your project.
Live demo: negomi.github.io/react-burger-menu
To build the examples locally, first make sure you're using Node <11.0.0. Then run:
npm install
npm start
Then open localhost:8000 in a browser.
The test suite uses Mocha, Chai and Sinon, with jsdom.
To run the tests once, run:
npm test
To run them with a watcher, run:
npm run test:watch
The easiest way to use react-burger-menu is to install it from npm and include it in your own React build process (using Browserify, Webpack, etc).
You can also use the standalone build by including dist/react-burger-menu.js in your page. If you use this, make sure you have already included React, and it is available as a global variable.
Version 3.x uses Hooks, so if you're using React 16.8+:
npm install react-burger-menu --save
If you're using an earlier version of React:
npm install react-burger-menu@^2.9.2 --save
Items for the sidebar should be passed as child elements of the component using JSX.
import { slide as Menu } from 'react-burger-menu'
class Example extends React.Component {
showSettings (event) {
event.preventDefault();
.
.
.
}
render () {
// NOTE: You also need to provide styles, see https://github.com/negomi/react-burger-menu#styling
return (
<Menu>
<a id="home" className="menu-item" href="https://github.com/negomi/react-burger-menu/blob/HEAD//">Home</a>
<a id="about" className="menu-item" href="https://github.com/negomi/react-burger-menu/blob/HEAD//about">About</a>
<a id="contact" className="menu-item" href="https://github.com/negomi/react-burger-menu/blob/HEAD//contact">Contact</a>
<a onClick={ this.showSettings } className="menu-item--small" href="">Settings</a>
</Menu>
);
}
}
The example above imported slide which renders a menu that slides in on the page when the burger icon is clicked. To use a different animation you can substitute slide with any of the following (check out the demo to see the animations in action):
slidestackelasticbubblepushpushRotatescaleDownscaleRotatefallDownrevealSome animations require certain other elements to be on your page:
Page wrapper - an element wrapping the rest of the content on your page (except elements with fixed positioning - see the wiki for details), placed after the menu component
<Menu pageWrapId={ "page-wrap" } />
<main id="page-wrap">
.
.
.
</main>
Outer container - an element containing everything, including the menu component
<div id="outer-container">
<Menu pageWrapId={ "page-wrap" } outerContainerId={ "outer-container" } />
<main id="page-wrap">
.
.
.
</main>
</div>
If you are using an animation that requires either/both of these elements, you need to give the element an ID, and pass that ID to the menu component as the pageWrapId and outerContainerId props respectively.
Check this table to see which animations require these elements:
| Animation | pageWrapId | outerContainerId |
|---|---|---|
slide | ||
stack | ||
elastic | â | â |
bubble | ||
push | â | â |
pushRotate | â | â |
scaleDown | â | â |
scaleRotate | â | â |
fallDown | â | â |
reveal | â | â |
The menu opens from the left by default. To have it open from the right, use the right prop. It's just a boolean so you don't need to specify a value. Then set the position of the button using CSS.
<Menu right />
You can specify the width of the menu with the width prop. The default is 300.
<Menu width={ 280 } />
<Menu width={ '280px' } />
<Menu width={ '20%' } />
You can control whether the sidebar is open or closed with the isOpen prop. This is useful if you need to close the menu after a user clicks on an item in it, for example, or if you want to open the menu from some other button in addition to the standard burger icon. The default value is false.
// To render the menu open
<Menu isOpen />
<Menu isOpen={ true } />
// To render the menu closed
<Menu isOpen={ false } />
You can see a more detailed example of how to use isOpen here.
Note: If you want to render the menu open initially, you will need to set this property in your parent component's componentDidMount() function.
If you keep the menu state yourself it might be convenient to pass a custom function to be used when the user triggers something that should open the menu.
Called when:
<Menu onOpen={ handleOnOpen } />
Note: The menu will NOT open automatically if you pass this prop, so you must handle it yourself.
If you keep the menu state yourself it might be convenient to pass a custom function to be used when the user triggers something that should close the menu.
Called when:
<Menu onClose={ handleOnClose } />
Note: The menu will NOT close automatically if you pass this prop, so you must handle it yourself.
You can detect whether the sidebar is open or closed by passing a callback function to onStateChange. The callback will receive an object containing the new state as its first argument.
var isMenuOpen = function(state) {
return state.isOpen;
};
<Menu onStateChange={ isMenuOpen } />
By default, the menu will close when the Escape key is pressed. To disable this behavior, you can pass the disableCloseOnEsc prop. This is useful in cases where you want the menu to be open all the time, for example if you're implementing a responsive menu that behaves differently depending on the browser width.
<Menu disableCloseOnEsc />
keydown handlerFor more control over global keypress functionality, you can override the handler that this component sets for window.addEventListener('keydown', handler), and pass a custom function. This could be useful if you are using multiple instances of this component, for example, and want to implement functionality to ensure that a single press of the Escape key closes them all.
const closeAllMenusOnEsc = (e) => {
e = e || window.event;
if (e.key === 'Escape' || e.keyCode === 27) {
this.setState({areMenusOpen: false});
}
};
<MenuOne customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} />
<MenuTwo customOnKeyDown={closeAllMenusOnEsc} isOpen={areMenusOpen} />
Note: Using this prop will disable all the default 'close on Escape' functionality, so you will need to handle this (including determining which key was pressed) yourself.
You can turn off the default overlay with noOverlay.
<Menu noOverlay />
You can disable the overlay click event (i.e. prevent overlay clicks from closing the menu) with disableOverlayClick. This can either be a boolean, or a function that returns a boolean.
<Menu disableOverlayClick />
<Menu disableOverlayClick={() => shouldDisableOverlayClick()} />
You can disable all transitions/animations by passing noTransition.
<Menu noTransition />
This is useful if you want the menu to remain open across re-mounts, for example during SPA route changes.
You can replace the default bars that make up the burger and cross icons with custom ReactElements. Pass them as the customBurgerIcon and customCrossIcon props respectively.
<Menu customBurgerIcon={ <img src="https://raw.githubusercontent.com/negomi/react-burger-menu/HEAD/img/icon.svg" /> } />
<Menu customCrossIcon={ <img src="https://raw.githubusercontent.com/negomi/react-burger-menu/HEAD/img/cross.svg" /> } />
You should adjust their size using the .bm-burger-button and .bm-cross-button classes, but the element itself will have the class .bm-icon or .bm-cross if you need to access it directly.
You can also disable the icon elements so they won't be included at all, by passing false to these props.
<Menu customBurgerIcon={ false } />
<Menu customCrossIcon={ false } />
This can be useful if you want exclusive external control of the menu, using the isOpen prop.
There are optional id and className props, which will simply add an ID or custom className to the rendered menu's outermost element. This is not required for any functionality, but could be useful for things like styling with CSS modules.
<Menu id={ "sidebar" } className={ "my-menu" } />
You can also pass custom classNames to the other elements:
<Menu burgerButtonClassName={ "my-class" } />
<Menu burgerBarClassName={ "my-class" } />
<Menu crossButtonClassName={ "my-class" } />
<Menu crossClassName={ "my-class" } />
<Menu menuClassName={ "my-class" } />
<Menu morphShapeClassName={ "my-class" } />
<Menu itemListClassName={ "my-class" } />
<Menu overlayClassName={ "my-class" } />
And to the html and body elements (applied when the menu is open):
<Menu htmlClassName={ "my-class" } />
<Menu bodyClassName={ "my-class" } />
Note: Passing these props will prevent the menu from applying styles to the html or body elements automatically. See here for more explanation.
By default, the menu will set focus on the first item when opened. This is to help with keyboard navigation. If you don't want this functionality, you can pass the disableAutoFocus prop.
<Menu disableAutoFocus />
The menu's children are all wrapped in a nav element by default, as navigation is likely the most common use case for this component. However, it's a general purpose sidebar, so you can change this to a div if you're not using it for navigation:
<Menu itemListElement="div" />
All the animations are handled internally by the component. However, the visual styles (colors, fonts etc.) are not, and need to be supplied, either with CSS or with a JavaScript object passed as the styles prop.
The component has the following helper classes:
/* Position and sizing of burger button */
.bm-burger-button {
position: fixed;
width: 36px;
height: 30px;
left: 36px;
top: 36px;
}
/* Color/shape of burger icon bars */
.bm-burger-bars {
background: #373a47;
}
/* Color/shape of burger icon bars on hover*/
.bm-burger-bars-hover {
background: #a90000;
}
/* Position and sizing of clickable cross button */
.bm-cross-button {
height: 24px;
width: 24px;
}
/* Color/shape of close button cross */
.bm-cross {
background: #bdc3c7;
}
/*
Sidebar wrapper styles
Note: Beware of modifying this element as it can break the animations - you should not need to touch it in most cases
*/
.bm-menu-wrap {
position: fixed;
height: 100%;
}
/* General sidebar styles */
.bm-menu {
background: #373a47;
padding: 2.5em 1.5em 0;
font-size: 1.15em;
}
/* Morph shape necessary with bubble or elastic */
.bm-morph-shape {
fill: #373a47;
}
/* Wrapper for item list */
.bm-item-list {
color: #b8b7ad;
padding: 0.8em;
}
/* Individual item */
.bm-item {
display: inline-block;
}
/* Styling of overlay */
.bm-overlay {
background: rgba(0, 0, 0, 0.3);
}
The same styles can be written as a JavaScript object like this:
var styles = {
bmBurgerButton: {
position: 'fixed',
width: '36px',
height: '30px',
left: '36px',
top: '36px'
},
bmBurgerBars: {
background: '#373a47'
},
bmBurgerBarsHover: {
background: '#a90000'
},
bmCrossButton: {
height: '24px',
width: '24px'
},
bmCross: {
background: '#bdc3c7'
},
bmMenuWrap: {
position: 'fixed',
height: '100%'
},
bmMenu: {
background: '#373a47',
padding: '2.5em 1.5em 0',
fontSize: '1.15em'
},
bmMorphShape: {
fill: '#373a47'
},
bmItemList: {
color: '#b8b7ad',
padding: '0.8em'
},
bmItem: {
display: 'inline-block'
},
bmOverlay: {
background: 'rgba(0, 0, 0, 0.3)'
}
}
<Menu styles={ styles } />
Because this project uses CSS3 features, it's only meant for modern browsers. Some browsers currently fail to apply some of the animations correctly.
Chrome and Firefox have full support, but Safari and IE have strange behavior for some of the menus.
Check the FAQ (https://github.com/negomi/react-burger-menu/wiki/FAQ) to see if your question has been answered already, or open a new issue.
MIT