react-aria-menubutton icon indicating copy to clipboard operation
react-aria-menubutton copied to clipboard

Keeping Menu open by default

Open karol-majewski opened this issue 5 years ago • 0 comments

Hello and thank you for your work. This library has been of great help to me.

Use case

I'm using react-aria-menubutton to help me handle keyboard navigation in my forms. One of them lives inside a modal. When the modal is open, I want my menu to be visible immediately, without having to trigger it by pressing a button.

What I tried

Passing isOpen

The type definitions say I could pass isOpen to Wrapper.

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/ec03e77d0a0c84d599b46211befac932160d5a0f/types/react-aria-menubutton/index.d.ts#L44

This doesn't seem to be the case. React passes that prop down to the underlying div and displays a warning.

Warning: React does not recognize the `isOpen` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `isopen` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

Passing open

The type definitions allow me to pass a prop called open, but it doesn't come directly from WrapperProps. It's inherited from AllHTMLAttributes<T> and has no effect.

Using openMenu

When I add an id=menu to my Wrapper and try to open the menu programmatically, I get a runtime exception.

I'm using a function component. It doesn't matter if I use useEffect or useLayoutEffect to run the effect — at the time they're executed, my menu hasn't mounted yet, and an element of id=menu doesn't exist.

  React.useLayoutEffect(() => {
    openMenu('menu');
  });

  React.useEffect(() => {
    openMenu('menu');
  });

  return (
     <Wrapper id="menu">
    ...
  )

I tried providing a ref to Wrapper and calling openMenu only when I know the underlying HTMLElement is mounted, but unfortunately Wrapper doesn't forward React refs. The only workaround that seems to be working is to do:

  React.useLayoutEffect(() => {
    if (document.getElementById('menu')) {
      ARIA.openMenu('menu');
    }
  });

which works, but because it relies on a low-level DOM API, it goes against the declarative model of React.

The question

How can I render my menu open from the start?

Related

  • #48 suggests Wrapper should accept isOpen
  • #16 suggests isOpen is not meant to manipulate state and mentions startOpen that doesn't exist today

karol-majewski avatar Dec 04 '19 16:12 karol-majewski