Skip to content
Imogen edited this page Jun 23, 2022 · 19 revisions

Frequently Asked Questions

I imported the menu but the burger icon isn't showing and the menu opens when I click anywhere.

You most likely need to add styles. The burger icon is there, but invisible, and taking up the entire screen because it defaults to 100% width/height and you haven't given it a size/background color yet.

From the docs on styling:

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.

Can I change the transition property of the menu?

Yes, but it's not recommended for animations other than Slide due to how other page elements are designed to move with the transition.

You can access it through the bmMenuWrap key of the styles prop:

var styles = {
  bmMenuWrap: {
    transition: ''
  }
}

<Menu styles={ styles } />

Or with CSS:

.bm-menu-wrap {
  transition: '' !important;
}

I have a fixed header, but it's scrolling with the rest of the page when I open the menu.

Unlike the rest of your content, fixed elements need to be placed outside your page-wrap element, so your layout structure will look something like this:

<div id="outer-container">
  <header>I am a fixed header!</header>
  <Menu pageWrapId={ "page-wrap" } outerContainerId={ "outer-container" } />
  <main id="page-wrap">
    .
    .
    .
  </main>
</div>

A common use for this is a fixed header, but the same applies to any elements you want to remain fixed and positioned relative to the viewport.

This package is making my Webpack bundle huge due to snapsvg-cjs.

If you're not using one of the animations that needs Snap.svg (Elastic or Bubble), then you can import the menu like this:

import Menu from 'react-burger-menu/lib/menus/slide'

This will keep Snap.svg out of your bundle.

I want to control the open state programmatically but I don't understand how to use the isOpen prop.

First, you need to store the menu state somewhere outside the component (the simplest place would be in a parent component's state, so I'll use that to demonstrate). Now you have control of that state (i.e. the menu is a 'controlled component'), you can set it to whatever you want via other actions (e.g. a click on a menu item or a custom burger icon). Then all you have to do is pass that state down (via the isOpen prop), and the menu will open/close according to the state you pass.

The code would look something like this:

class ParentComponent extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      menuOpen: false
    }
  }

  // This keeps your state in sync with the opening/closing of the menu
  // via the default means, e.g. clicking the X, pressing the ESC key etc.
  handleStateChange (state) {
    this.setState({menuOpen: state.isOpen})  
  }
  
  // This can be used to close the menu, e.g. when a user clicks a menu item
  closeMenu () {
    this.setState({menuOpen: false})
  }

  // This can be used to toggle the menu, e.g. when using a custom icon
  // Tip: You probably want to hide either/both default icons if using a custom icon
  // See https://github.com/negomi/react-burger-menu#custom-icons
  toggleMenu () {
    this.setState(state => ({menuOpen: !state.menuOpen}))
  }

  render () {
    return (
      <div>
        <Menu 
          isOpen={this.state.menuOpen}
          onStateChange={(state) => this.handleStateChange(state)}
        >
          <a onClick={() => this.closeMenu()}>Home</a>
          <a onClick={() => this.closeMenu()}>About</a>
          <a onClick={() => this.closeMenu()}>Contact</a>
          <a onClick={() => this.closeMenu()}>Settings</a>
        </Menu>
        <CustomIcon onClick={() => this.toggleMenu()} />
      </div>
    )
  }
}

Here is another example using the useState hook, the useContext hook, and the Context API in React:

import React, { useState, useContext } from 'react'
import {slide as Menu} from 'react-burger-menu'

// make a new context
const MyContext = React.createContext();

// create the provider
const MyProvider = (props) => {
  const [menuOpenState, setMenuOpenState] = useState(false)
  
  return (
    <MyContext.Provider value={{
      isMenuOpen: menuOpenState,
      toggleMenu: () => setMenuOpenState(!menuOpenState),
      stateChangeHandler: (newState) => setMenuOpenState(newState.isOpen)
    }}>
      {props.children}
    </MyContext.Provider>
  )
}

// create a button that calls a context function to set a new open state when clicked
const Button = () => {
  const ctx = useContext(MyContext)
  return (
    <button onClick={ctx.toggleMenu}>Toggle menu</button>
  )
}

// create a navigation component that wraps the burger menu
const Navigation = () => {
  const ctx = useContext(MyContext)

  return (
    <Menu 
      customBurgerIcon={false}
      isOpen={ctx.isMenuOpen}
      onStateChange={(state) => ctx.stateChangeHandler(state)}
    />
  )
}

// default export here
const App = () => {
  return (
    <MyProvider>
      <div>
        <Button />
        <Navigation />
      </div>
    </MyProvider>
  )
}

export default App;

My page content is still scrollable when the menu is open.

The solution to this will vary depending on your element hierarchy, but the simplest approach is to set height: 100%; on every element from your 'page wrap' element and above (including body and html). Then on the 'page wrap' element itself, also set overflow: auto;. This is how the demo page achieves the lack of scrolling.

'Page wrap' element means either the one with the explicit pageWrapId, or if you're using a simpler menu, just whichever element is wrapping your page content.

This is some example markup, showing every element you would need to apply height: 100%; to (it doesn't have to be applied inline, that's just for demo purposes):

<html style="height: 100%;">
  <head />
  <body style="height: 100%;">
    <div id="app" style="height: 100%;">
      <div id="outer-container" style="height: 100%;">
        <Menu />
        <div id="page-wrap" style="height: 100%; overflow: auto;">
          <!-- Your page content -->
        </div>
      </div>
    </div>
  </body>
</html>

You can refer to the demo page for a working example.

Why is overflow-x: hidden being set on the html and body elements?

This is to avoid horizontal scrolling issues present in some browsers when the menu is open. If it's causing you problems, you can prevent this property being added by passing htmlClassName and bodyClassName props. When you pass these, no styles will be applied to the html/body elements automatically, and you can instead use the classes to apply any styles you need.

Is there a way to add dropdowns or submenus inside this component?

Yes, react-burger-menu just provides a container. It has no opinions about what you put inside it, so you can build submenus or dropdowns however you like.

You can pass any component as a child of the menu, so a dropdown menu from a library or one that you implement yourself should just work.

If you were looking for a package that supports multilevel nested menus out of the box, it looks like there are a few others that support it, e.g. https://www.npmjs.com/package/react-sidenav

Or this one, which you might be able to use inside react-burger-menu: https://github.com/gholme4/react-nested-menu