A list of actions in a dropdown, enhanced with keyboard navigation.
import { MenuTrigger, Menu, MenuItem } from '@backstage/ui';
<MenuTrigger>
<Button>Menu</Button>
<Menu>
<MenuItem id="apple">Apple</MenuItem>
<MenuItem id="banana">Banana</MenuItem>
<MenuItem id="blueberry">Blueberry</MenuItem>
<MenuSeparator />
<SubmenuTrigger>
<MenuItem>Vegetables</MenuItem>
<Menu>
<MenuItem id="carrot">Carrot</MenuItem>
<MenuItem id="tomato">Tomato</MenuItem>
<MenuItem id="potato">Potato</MenuItem>
</Menu>
</SubmenuTrigger>
</Menu>
</MenuTrigger>
MenuTrigger
is a wrapper component that combines a button or other trigger element with a menu displayed in a popover.SubmenuTrigger
is a wrapper component that combines a MenuItem
with a menu displayed in a popover.Menu
is a container component that contains a list of menu items or sections.MenuListBox
is a container component that contains a list of menu items or sections.MenuAutocomplete
is a container component that contains a list of menu items or sections.MenuAutocompleteListbox
is a container component that contains a list of menu items or sections.MenuItem
is an individual interactive item in the menu.MenuListBoxItem
is an individual interactive item in the menu list box.MenuSeparator
is a component that renders a horizontal line to separate menu items.MenuSection
is a component that renders a section in the menu.MenuTrigger
accepts exactly two children: the first child should be the trigger element, and second child should be
one of the menu containers containing the menu.
Prop | Type | Default | Responsive |
---|---|---|---|
isOpen | boolean | - | No |
defaultOpen | boolean | - | No |
onOpenChange | (isOpen: boolean) => void | - | No |
The SubmenuTrigger
accepts exactly two children: the first child should be the MenuItem
which triggers opening
of the submenu, and second child should be one of the menu containers containing the submenu.
Prop | Type | Default | Responsive |
---|---|---|---|
delay | number | 200 | No |
Menu
is a container component that contains a list of menu items or sections.
Prop | Type | Default | Responsive |
---|---|---|---|
disabledKeys | Iterable<Key> | - | No |
selectionMode | nonesinglemultiple | - | No |
selectedKeys | allIterable<Key> | - | No |
defaultSelectedKeys | allIterable<Key> | - | No |
placement | bottombottom leftbottom rightbottom startbottom endtoptop lefttop righttop starttop endleftleft topleft bottomstartstart topstart bottomrightright topright bottomendend topend bottom | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuListBox
is a container component that contains a list of menu items or sections.
Prop | Type | Default | Responsive |
---|---|---|---|
disabledKeys | Iterable<Key> | - | No |
selectionMode | nonesinglemultiple | - | No |
selectedKeys | allIterable<Key> | - | No |
defaultSelectedKeys | allIterable<Key> | - | No |
placement | bottombottom leftbottom rightbottom startbottom endtoptop lefttop righttop starttop endleftleft topleft bottomstartstart topstart bottomrightright topright bottomendend topend bottom | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuAutocomplete
is a container component that contains a list of menu items or sections.
Prop | Type | Default | Responsive |
---|---|---|---|
placement | bottombottom leftbottom rightbottom startbottom endtoptop lefttop righttop starttop endleftleft topleft bottomstartstart topstart bottomrightright topright bottomendend topend bottom | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuAutocompleteListbox
is a container component that contains a list of menu items or sections.
Prop | Type | Default | Responsive |
---|---|---|---|
placement | bottombottom leftbottom rightbottom startbottom endtoptop lefttop righttop starttop endleftleft topleft bottomstartstart topstart bottomrightright topright bottomendend topend bottom | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuItem
is an individual interactive item in the menu.
Prop | Type | Default | Responsive |
---|---|---|---|
id | Key | - | No |
value | string | - | No |
textValue | string | - | No |
isDisabled | boolean | - | No |
href | string | - | No |
onAction | (event) => void | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuListBoxItem
is an individual interactive item in the menu list box.
Prop | Type | Default | Responsive |
---|---|---|---|
id | Key | - | No |
value | string | - | No |
textValue | string | - | No |
isDisabled | boolean | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuSection
is a component that renders a section in the menu.
Prop | Type | Default | Responsive |
---|---|---|---|
title | string | - | No |
className | string | - | No |
style | CSSProperties | - | No |
MenuSeparator
is a component that renders a horizontal line to separate menu items.
Prop | Type | Default | Responsive |
---|---|---|---|
className | string | - | No |
style | CSSProperties | - | No |
You can nest menus to create a more complex navigation structure. It is important to use the placement
prop to ensure
the submenu is displayed in the correct position. The best practice is to use the right top
placement for the submenu.
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<Menu>
<MenuItem>Edit</MenuItem>
<MenuItem>Duplicate</MenuItem>
<SubmenuTrigger>
<MenuItem>Submenu</MenuItem>
<Menu placement="right top">
<MenuItem>Edit</MenuItem>
<MenuItem>Duplicate</MenuItem>
<MenuItem>Rename</MenuItem>
<MenuSeparator />
<MenuItem>Share</MenuItem>
<MenuItem>Move</MenuItem>
<MenuSeparator />
<MenuItem iconStart={<RiChat1Line />}>Feedback</MenuItem>
</Menu>
</SubmenuTrigger>
</Menu>
</MenuTrigger>
You can use the iconStart
prop to add an icon to the menu item.
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<Menu>
<MenuItem iconStart={<RiFileCopyLine />}>Copy</MenuItem>
<MenuItem iconStart={<RiEdit2Line />}>Rename</MenuItem>
<MenuItem iconStart={<RiChat1Line />}>Send feedback</MenuItem>
</Menu>
</MenuTrigger>
You can use the href
prop to add a link to the menu item. This is using our router provider under the hood
to work for both internal and external links.
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<Menu>
<MenuItem href="/home">Internal link</MenuItem>
<MenuItem href="https://www.google.com" target="_blank">
External link
</MenuItem>
<MenuItem href="mailto:test@test.com">Email link</MenuItem>
</Menu>
</MenuTrigger>
You can use the MenuSection
component to add a section to the menu.
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<Menu>
<MenuSection title="My Account">
<MenuItem iconStart={<RiUserLine />}>Profile</MenuItem>
<MenuItem iconStart={<RiSettingsLine />}>Settings</MenuItem>
</MenuSection>
<MenuSection title="Support">
<MenuItem iconStart={<RiQuestionLine />}>Help Center</MenuItem>
<MenuItem iconStart={<RiCustomerService2Line />}>
Contact Support
</MenuItem>
<MenuItem iconStart={<RiChat1Line />}>Feedback</MenuItem>
</MenuSection>
</Menu>
</MenuTrigger>
You can use the MenuSeparator
component to add a separator to the menu.
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<Menu>
<MenuItem>Edit</MenuItem>
<MenuItem>Duplicate</MenuItem>
<MenuItem>Rename</MenuItem>
<MenuSeparator />
<MenuItem>Share</MenuItem>
<MenuItem>Move</MenuItem>
<MenuSeparator />
<MenuItem iconStart={<RiChat1Line />}>Feedback</MenuItem>
</Menu>
</MenuTrigger>
You can use the MenuAutocomplete
component to add a autocomplete to the menu.
<MenuTrigger isOpen>
<Button aria-label="Menu">Menu</Button>
<MenuAutocomplete placeholder="Filter">
<MenuItem>Create new file...</MenuItem>
<MenuItem>Create new folder...</MenuItem>
<MenuItem>Assign to...</MenuItem>
<MenuItem>Assign to me</MenuItem>
<MenuItem>Change status...</MenuItem>
<MenuItem>Change priority...</MenuItem>
<MenuItem>Add label...</MenuItem>
<MenuItem>Remove label...</MenuItem>
</MenuAutocomplete>
</MenuTrigger>
You can use the MenuListBox
component to add a list box to the menu.
const [selected, setSelected] = useState<Selection>(
new Set(['blueberry']),
);
<Flex direction="column" gap="2" align="start">
<Text>Selected: {Array.from(selected).join(', ')}</Text>
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<MenuAutocompleteListbox
selectedKeys={selected}
onSelectionChange={setSelected}
>
{options.map(option => (
<MenuListBoxItem key={option.value} id={option.value}>
{option.label}
</MenuListBoxItem>
))}
</MenuAutocompleteListbox>
</MenuTrigger>
</Flex>
You can use the MenuListBox
component to add a list box to the menu. You can also use the selectionMode
prop to
allow multiple selection.
const [selected, setSelected] = useState<Selection>(
new Set(['blueberry', 'cherry']),
);
<Flex direction="column" gap="2" align="start">
<Text>Selected: {Array.from(selected).join(', ')}</Text>
<MenuTrigger>
<Button aria-label="Menu">Menu</Button>
<MenuAutocompleteListbox
selectionMode="multiple"
selectedKeys={selected}
onSelectionChange={setSelected}
>
{options.map(option => (
<MenuListBoxItem key={option.value} id={option.value}>
{option.label}
</MenuListBoxItem>
))}
</MenuAutocompleteListbox>
</MenuTrigger>
</Flex>
Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below.
bui-Menu
bui-MenuPopover
bui-MenuContent
bui-MenuSection
bui-MenuSectionHeader
bui-MenuItem
bui-MenuItemListBox
bui-MenuItemListBoxCheck
bui-MenuItemContent
bui-MenuItemArrow
bui-MenuSeparator
bui-MenuSearchField
bui-MenuSearchFieldInput
bui-MenuSearchFieldClear
bui-MenuEmptyState