0

I'm using Tailwind CSS and the HeadlessUI Menu component for React.

The menu items are components that each contain a button that opens a dialog.

This works correctly when using the menu with the mouse. But when using the menu with the keyboard, the Menu component doesn't know to trigger an onClick event on the buttons contained in DataImporter and DataGenerator, so nothing happens when you press Enter.

Here's a stripped-down example:

import { useState, Fragment, useRef, ReactElement } from 'react'
import cx from 'classnames'
import * as Headless from '@headlessui/react'

export const App = () => {
  const menuItems = [<DataImporter />, <DataGenerator />]
  return (
    <div className="flex flex-col space-y-4 border divide-y w-full max-w-lg bg-white">
      <div className="p-10 space-y-4">
        <Headless.Menu as="div" className="relative inline-block text-left">
          <Headless.Menu.Button className="button">Menu</Headless.Menu.Button>
          <Headless.Menu.Items
            unmount={false}
            static
            className="absolute mt-2 w-56 border divide-y rounded bg-white"
          >
            {menuItems.map((item, i) => (
              <Headless.Menu.Item key={i}>
                {({ active }) => (
                  <span
                    className={cx({
                      'block cursor-pointer px-4 py-2': true,
                      'bg-gray-100 text-gray-900': active,
                    })}
                    children={item}
                  />
                )}
              </Headless.Menu.Item>
            ))}
          </Headless.Menu.Items>
        </Headless.Menu>
      </div>
    </div>
  )
}

const DataImporter = () => {
  const [isOpen, setIsOpen] = useState(false)
  const open = () => setIsOpen(true)
  const close = () => setIsOpen(false)
  return (
    <>
      <button onClick={open}>Import data</button>
      <Headless.Transition.Root show={isOpen}>
        <Headless.Dialog as="div" onClose={close}>
          <Backdrop />
          <div className="fixed inset-0 z-10 flex min-h-full justify-center p-4 items-center">
            <Headless.Dialog.Panel className="w-full max-w-lg p-6 rounded bg-white space-y-2">
              <h3>Import data</h3>
              <div className="text-right">
                <button className="button" onClick={close} children="OK" />
              </div>
            </Headless.Dialog.Panel>
          </div>
        </Headless.Dialog>
      </Headless.Transition.Root>
    </>
  )
}

const DataGenerator = () => {
  const [isOpen, setIsOpen] = useState(false)
  const open = () => setIsOpen(true)
  const close = () => setIsOpen(false)
  return (
    <>
      <button onClick={open}>Generate data</button>
      <Headless.Transition.Root show={isOpen}>
        <Headless.Dialog as="div" onClose={close}>
          <Backdrop />
          <div className="fixed inset-0 z-10 flex min-h-full justify-center p-4 items-center">
            <Headless.Dialog.Panel className="w-full max-w-lg p-6 rounded bg-white space-y-2">
              <h3>Generate data</h3>
              <div className="text-right">
                <button className="button" onClick={close} children="OK" />
              </div>
            </Headless.Dialog.Panel>
          </div>
        </Headless.Dialog>
      </Headless.Transition.Root>
    </>
  )
}

const Backdrop = () => (
  <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
)

There's a live example here: https://oil-gorgeous-haze.glitch.me

Source code here: http://glitch.com/edit/#!/oil-gorgeous-haze?path=src%2FApp.tsx%3A58%3A0

Is there a way to get the MenuItem component to trigger the onClick event on the button contained in either of the dialog components?

Herb Caudill
  • 50,043
  • 39
  • 124
  • 173

0 Answers0