Back to Evergreen

Usage

docs/documentation/components/menu.mdx

7.1.96.2 KB
Original Source

Usage

Evergreen exports multiple component to help create menus. All components are accessible through the Menu component.

  • Menu: menu wrapper, helps with focus management.
  • Menu.Item: single menu item button. Contains labels and icons.
  • Menu.Group: group menu items together.
  • Menu.Divider: menu divider to divide menu groups visually.
  • Menu.OptionsGroup: menu group which works like a radio group.

Focus management

The Menu component is used to help with focus management.

  • Arrow down on a button will bring focus inside the popover.
  • Arrow keys within the menu will cycle through all of the menu items and skip disabled items.
  • The Home key (fn + arrow left) will go to the first item.
  • The End key (fn + arrow right) will go to the last item.

All examples below will show the Menu inside of a Popover. It is important to understand the Menu component by itself does not manage a dropdown interaction.

jsx
<Menu>
  <Menu.Group>
    <Menu.Item>Share...</Menu.Item>
    <Menu.Item>Move...</Menu.Item>
    <Menu.Item>Rename...</Menu.Item>
  </Menu.Group>
  <Menu.Divider />
  <Menu.Group>
    <Menu.Item intent="danger">Delete...</Menu.Item>
  </Menu.Group>
</Menu>

Using onSelect handlers

Menu items support a onSelect handler that is triggered on click and enter + space key down.

jsx
<Menu.Item onSelect={() => toaster.notify('Hello world')}>Say hello</Menu.Item>
jsx
<Popover
  position={Position.BOTTOM_LEFT}
  content={
    <Menu>
      <Menu.Group>
        <Menu.Item onSelect={() => toaster.notify('Share')}>Share...</Menu.Item>
        <Menu.Item onSelect={() => toaster.notify('Move')}>Move...</Menu.Item>
        <Menu.Item onSelect={() => toaster.notify('Rename')} secondaryText="⌘R">
          Rename...
        </Menu.Item>
      </Menu.Group>
      <Menu.Divider />
      <Menu.Group>
        <Menu.Item onSelect={() => toaster.danger('Delete')} intent="danger">
          Delete...
        </Menu.Item>
      </Menu.Group>
    </Menu>
  }
>
  <Button marginRight={16}>Without Icons</Button>
</Popover>

The onSelect handlers are omitted for brevity.

jsx
<Popover
  position={Position.BOTTOM_LEFT}
  content={
    <Menu>
      <Menu.Group>
        <Menu.Item icon={PeopleIcon}>Share...</Menu.Item>
        <Menu.Item icon={CircleArrowRightIcon}>Move...</Menu.Item>
        <Menu.Item icon={EditIcon} secondaryText="⌘R">
          Rename...
        </Menu.Item>
      </Menu.Group>
      <Menu.Divider />
      <Menu.Group>
        <Menu.Item icon={TrashIcon} intent="danger">
          Delete...
        </Menu.Item>
      </Menu.Group>
    </Menu>
  }
>
  <Button marginRight={16}>With Icons</Button>
</Popover>
jsx
<Popover
  position={Position.BOTTOM_LEFT}
  content={
    <Menu>
      <Menu.Group>
        <Menu.Item disabled icon={PeopleIcon}>
          Share...
        </Menu.Item>
        <Menu.Item icon={CircleArrowRightIcon}>Move...</Menu.Item>
        <Menu.Item icon={EditIcon} secondaryText="⌘R">
          Rename...
        </Menu.Item>
      </Menu.Group>
      <Menu.Divider />
      <Menu.Group>
        <Menu.Item disabled icon={TrashIcon} intent="danger">
          Delete...
        </Menu.Item>
      </Menu.Group>
    </Menu>
  }
>
  <Button marginRight={16}>With Disabled Items</Button>
</Popover>

Groups with titles

The onSelect handlers are omitted for brevity.

jsx
<Popover
  position={Position.BOTTOM_LEFT}
  content={
    <Menu>
      <Menu.Group title="Actions">
        <Menu.Item icon={PeopleIcon}>Share...</Menu.Item>
        <Menu.Item icon={CircleArrowRightIcon}>Move...</Menu.Item>
        <Menu.Item icon={EditIcon} secondaryText="⌘R">
          Rename...
        </Menu.Item>
      </Menu.Group>
      <Menu.Divider />
      <Menu.Group title="destructive">
        <Menu.Item icon={TrashIcon} intent="danger">
          Delete...
        </Menu.Item>
      </Menu.Group>
    </Menu>
  }
>
  <Button marginRight={16}>With Group Titles</Button>
</Popover>

The Menu.OptionsGroup is useful inside of table headers to help with sorting and filtering options.

jsx
function MenuOptionsGroupExample() {
  const [selectedOrder, setSelectedOrder] = React.useState('asc')
  const [selectedField, setSelectedField] = React.useState('asc')
  return (
    <Menu>
      <Menu.OptionsGroup
        title="Order"
        options={[
          { label: 'Ascending', value: 'asc' },
          { label: 'Descending', value: 'desc' },
        ]}
        selected={selectedOrder}
        onChange={(selected) => setSelectedOrder(selected)}
      />
      <Menu.Divider />
      <Menu.OptionsGroup
        title="Show"
        options={[
          { label: 'Email', value: 'email' },
          { label: 'Phone', value: 'phone' },
          { label: 'State', value: 'state' },
          { label: 'Country', value: 'country' },
          { label: 'Type', value: 'type' },
        ]}
        selected={selectedField}
        onChange={(selected) => setSelectedField(selected)}
      />
    </Menu>
  )
}

Custom menu items

The Menu by itself offers focus management to elements inside of the component that either have [role="menuitemradio"] or [role="menuitem"].

The focus styles are currently not working in the docs, sorry for the inconvenience!

jsx
function CustomMenuItemExample() {
  const handleClick = React.useCallback(() => toaster.notify('Menu Item Clicked'), [])

  return (
    <Popover
      position={Position.BOTTOM_LEFT}
      content={
        <Menu>
          <Ul listStyle="square">
            <Link cursor="pointer" role="menuitem" onClick={handleClick}>
              <Li>Hey Evergreen,</Li>
            </Link>
            <Link cursor="pointer" role="menuitem" onClick={handleClick}>
              <Li>I want custom items</Li>
            </Link>
            <Pane borderTop={true} marginRight={majorScale(2)} />
            <Link cursor="pointer" role="menuitem" onClick={handleClick}>
              <Li>Oh sweet</Li>
            </Link>
          </Ul>
        </Menu>
      }
    >
      <Button>Custom Menu Items</Button>
    </Popover>
  )
}
jsx
<Menu></Menu>