Skip to content

React Router Link inside MenuButton #117

@OliverJAsh

Description

@OliverJAsh

I am trying to create a menu whereby each item is a link. The reason I want a link rather than a button:

  • accessibility, e.g. right click -> open in new tab
  • semantics, links are important for SEO

I understand that MenuButton supports a tag prop, so you could do something like <MenuButton tag="a" href="…" />, however in this case we need to use React Router's Link component rather than the a element. This is because React Router's Link component has special behaviour, such as calling history.pushState when the link is clicked (as opposed to performing a full page navigation).

For that reason, I tried the following:

  • nest a Link inside of a MenuButton
  • implement Wrapper's onSelection to run history.push, so it behaves the same as the link

Example: https://react-ts-bkz4fo.stackblitz.io/
Code: https://stackblitz.com/edit/react-ts-bkz4fo

One downside to this is we have to repeat the link in both Wrapper's onSelection and Link. But more importantly, doing this means that on click, two events handlers would be called rather than one: Link's onClick (which calls history.push) and Wrapper's onSelection. This in turn means history.push is called twice, resulting in an extraneous history entry.

Screenshot 2020-02-05 at 13 16 21

If you select an item from the menu, you'll see that the history contains double entries.

To workaround this, my first thought was to remove the Wrapper's onSelection and just use Link's onClick, however this means the link would not be actioned when navigating the menu via the keyboard.

Another idea I had was to preventDefault inside the Link's onClick. This fixes the issue of "two event handlers are called" whilst preserving the semantics/a11y of a link, except that command + click (shortcut to open in new tab) will not work.

Reach UI’s MenuButton solves this problem by providing a MenuLink that works just like a MenuItem except you can pass a custom link component to use instead of a: https://reacttraining.com/reach-ui/menu-button/#menulink-as. Furthermore, there is no need to implement a selection handler on the menu wrapper. Perhaps this library could do something similar?

Related: #85

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions