Dropdown Menu

These components can be used together to create a dropdown menu interface with inbuilt accessibility features.

They contain the bare minimum styling by default, and can be styled however you prefer. Each element also accepts an as prop, which can be used to define what kind of DOM or React element should be rendered.

Copy
Copied
<DropdownMenu>
  <DropdownMenuButton>This button triggers the menu</DropdownMenuButton>
  <DropdownMenuItems as="ul">
    <DropdownMenuItem as="li">an item</DropdownMenuItem>
    <DropdownMenuItem as="li">another item</DropdownMenuItem>
  </DropdownMenuItems>
</DropdownMenu>

DropdownMenu

The controller component. This must wrap all other components.

CSS Selectors

  • [data-flight-dropdown]
  • [data-flight-dropdown-open='false'] — styles applied when the items are hidden
  • [data-flight-dropdown-open='true'] — styles applied when the items are visible

DropdownMenuButton

The button that triggers hiding/showing of the menu items.

CSS Selectors

  • [data-flight-dropdown-button]

DropdownMenuItems

The container that wraps the items.

CSS Selectors

  • [data-flight-dropdown-items]

DropdownMenuItem

Contains a single item.

The onSelect prop should be used to determine what happens when the item is selected.

CSS Selectors

  • [data-flight-dropdown-item]

Accessing internal state

The DropdownMenu exposes some internal state, if you'd like to customise the behaviour.

isOpen Boolean = false (or the value passed to the DropdownMenu's initialOpen prop)
setIsOpen Function

If you want to access it, you have a few options:

With onSelect

The onSelect prop is called with an object containing { isOpen, setIsOpen }.

Copy
Copied
<DropdownMenuItem onSelect={({ setIsOpen }) => setIsOpen(false)}>
  Close the menu
</DropdownMenuItem>

useDropdownMenu

This hook can be used by any component inside the DropdownMenu in order to access the menu's state.

Copy
Copied
function Item(props) {
  const { setIsOpen } = useDropdownMenu();

  return (
    <li {...props}>
      <button onClick={() => setIsOpen(false)}>Close the menu</button>
    </li>
  );
}

<DropdownMenu>
  <DropdownMenuItems>
    <DropdownMenuItem as={Item} />
  </DropdownMenuItems>
</DropdownMenu>;

DropdownMenu render callback

Alternatively, you can provide a render callback as the child of the DropdownMenu.

Copy
Copied
<DropdownMenu>
  {({ setIsOpen }) => (
    <DropdownMenuItems>
      <li>
        <button onClick={() => setIsOpen(false)}>Close the menu</button>
      </li>
    </DropdownMenuItems>
  )}
</DropdownMenu>

Complete example

Hint: You can navigate the items with your keyboard

Copy
Copied
<Playground>
  <>
    <DropdownMenu>
      <DropdownMenuButton>Open</DropdownMenuButton>
      <DropdownMenuItems
        style={{
          background: "white",
          padding: "0.25em",
          listStyle: "none",
          zIndex: 999,
          border: "1px solid black",
        }}
      >
        <DropdownMenuItem onSelect={() => alert("hi!")}>
          hello!
        </DropdownMenuItem>
        <DropdownMenuItem onSelect={() => alert("great!")}>
          I'm open now
        </DropdownMenuItem>
        <DropdownMenuItem onSelect={({ setIsOpen }) => setIsOpen(false)}>
          <button>Close the menu!</button>
        </DropdownMenuItem>
      </DropdownMenuItems>
    </DropdownMenu>
  </>
</Playground>
Copyright © Norce 2023. All right reserved.