Last updated

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.

<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>

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

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

CSS Selectors

  • [data-flight-dropdown-button]

The container that wraps the items.

CSS Selectors

  • [data-flight-dropdown-items]

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.

isOpenBoolean= false (or the value passed to the DropdownMenu's initialOpen prop)
setIsOpenFunction

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

With onSelect

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

<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.

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>;

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

<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

<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>