negomi / react-burger-menu

:hamburger: An off-canvas sidebar component with a collection of effects and styles using CSS transitions and SVG path animations
http://negomi.github.io/react-burger-menu/
MIT License
5.05k stars 586 forks source link

Problems With Accessibility When Looping Over Menu Items #377

Closed greenymcgee closed 4 years ago

greenymcgee commented 4 years ago

Hello,

I'm currently working on a project where some nested menus have been requested in mobile view. Accomplishing this with react-burger-menu was pretty straightforward and works well overall, but I'm having some accessibility issues that I'm hoping we find a good solution for.

I noticed that you can override where the tabIndex prop gets set to if you build a component for your menu items like this.

const MenuItemComponent = (props) => (
  <div>
    <button tabIndex={props.tabIndex}>
      {props.text}
    </button>

    <div>//nested menu here</div>
  </div>
);

The problem that I'm having though is when you pair this functionality with a loop like this:

import { stack as ReactBurgerMenu } from 'react-burger-menu';

const someData = [
  { id: 1, text: 'hello' },
  { id:2, text: 'bye' },
];

const MenuItemComponent = (props) => (
  <div key={props.id}>
    <button tabIndex={props.tabIndex}>
      {props.text}
    </button>

    <div>//nested menu here</div>
  </div>
);

const BurgerMenu = () => (
  <ReactBurgerMenu>
    // these menu items will not get the tabIndex override that was coded
    {someData.map(MenuItemComponent)}

    // this will have the proper tabIndex override that was coded 
    <MenuItemComponent text="howdy" id={3} />
  </ReactBurgerMenu>
);

Ideally the above scenario would work, but what happens instead is that the outermost div of MenuItemComponent gets the react-burger-menu props of tabIndex, style, and className when coming from a loop.

myarete commented 4 years ago

I'm also having this same problem

negomi commented 4 years ago

Hey @greenymcgee / @altruisticsoftware,

The callback you pass to .map needs to return MenuItemComponent in order for the props to be applied to it properly (not the div inside it), so you can do this instead:

someData.map(data => <MenuItemComponent {...data} />)}