Skip to content

Menu

A Menu displays a list of available options, suggestions, or actions. They unfold from a control (e.g. a button, selector or input) after it is activated by a user.

Guidelines

When to use menus

Menus are intended to be used within other components such as Select, Lookup, or MenuButton. The Menu is displayed when the user interacts with the corresponding trigger element.

Specifications

Specification of Menu.

The menu is always displayed within a control or input, and it may include the following elements:

  1. Menu header (optional)
    An optional non-interactive item that serves to group other menu items under a clear title. This header can optionally include a start icon and a description.
  2. Menu items
    One or more menu items will appear within the menu. Refer to MenuItem to learn more about available display options.
  3. Footer (optional)
    An optional interactive footer can appear at the end of the menu items to display extra information or provide an access to further results. This footer can optionally include a start icon.
  4. Divider (optional)
    An optional divider will separate a set of related menu items when there is no clear title to group them.

Menus have a drop shadow in order to separate it more clearly from the content below. This shadow is a 20% opacity Black color with the X axis moved 0 pixels, the Y axis moved 2 pixels, and a 2 pixel blur.

Component limitations

The Menu component can accommodate numerous items, using a scrollbar when necessary. When scrolling, the optional menu footer remains fixed, ensuring consistent navigation.

It is recommended to avoid lengthy menus and utilize a scrollbar when the menu size exceeds manageable limits. The visible menu items may vary based on screen size, available space, and the component's context. Refer to each component's maximum recommendation to decide the suitable menu items.

Refer to the Menu component in Codex Figma.

Types

The base menu consists of a combination of menu items with an optional footer item positioned below the menu items group.

Example of Menu with different menu items and footer.

Menu items can include selectable options or trigger actions and can be customized with different text or media elements. Refer to MenuItem to learn more about on available customization options.

No results

When no results are present to show in the menu, a non-interactive "no results" message will appear within the menu.

Example of Menu with no results found.

Selection types

Menus can support different selection types depending on the component in which they are displayed:

  1. Single-selection
    Allows the user to select only one item from the menu at a time.
  2. Multi-selection
    Enables the user to select multiple items from the menu. A check icon is displayed next to the label to indicate that more than one item can be selected.

Types of selection of menu items: single-selection or multi-selection.

Grouping

Items within a menu can be grouped in two ways, depending on whether or not they have a clear title to show for the group:

  1. With title
    A prominent header can be added as a title to group a set of menu items.
  2. With no title
    In those cases where there is no clear title to include for the groups, a divider can be used to separate related items from other items in a menu.

Types of grouping items within a Menu: with header or with dividers.

Interaction states

The interaction states of the menu affect the entire menu (group of menu items), while individual menu item states are specifically defined within each respective item. The menu component has two main states:

Interaction states of Menu: default and loading.

  1. Default
  2. Loading

Best practices

Consider the following recommendations when using menus.

Media elements

Menus can incorporate different content and media types. Refer to MenuItem to explore all the available customization options for menu items.

Two different menus being displayed within Selects: one using start icons and the other using thumbnails.

Do:
  • Use icons to enhance the visual representation of text within menus.
  • Use thumbnails within menu items to display a small preview of an image.

Two different menus being displayed within Selects: one menu incorrectly using start icons with no text and the other one combining both icons and thumbnail in the same menu.

Don't:
  • Include only icons or thumbnails without labels within the menu as it would negatively impact accessibility and readability.
  • Combine menu items that use both icons and thumbnails within the same menu.

Grouping menu items

Menu using headers with a short label and longer description to group a list of multiple menu items.

Do:
  • Use headers to group one or more sets of menu items when there is a clear title for the group.
  • Keep the header’s label as short as possible to make the groups titles scannable, and use the header’s description in case you need to include additional information about the label.

Menu using headers with long labels with custom styles and dividers to group a list of multiple menu items.

Don't:
  • Combine headers and dividers to separate groups within the same menu.
  • Apply custom styles to the headers or dividers.
  • Indent the menu items under the header to avoid misalignment.
  • Make the header’s label too long. Instead, use the header’s description to provide any extra information about the label.

Menu using dividers to create three group of related menu items.

Do:
  • Use dividers to separate groups of items when there is no clear title to include for the groups.
  • Use dividers to organize a list of multiple items into clear and related groups.

Menu using dividers to separate each one of the three items in the menu.

Don't:
  • Use dividers to separate each one of the items in the menu. Instead, use dividers to group related items.
  • Use dividers to create groups if there are few items in the menu, such as only 2 or 3 items.

Content

Dropdown menus let readers choose one item from a set of options. Giving the choices a logical sequence makes them easy to scan and process.

Dropdown menus conveying examples of alphabetically organized options.

Do:
  • Alphabetize the drop-down choices, if appropriate, or organize them in the most logical order. Clear & Translatable

Dropdown menus conveying examples of unorganized options.

Don't:

Keyboard navigation

KeyFunction
TabWhen tabbing over a single-select menu, it selects the currently highlighted menu item.
Down arrowWhen the focus is placed on the component that contains the menu, it opens the menu. When the menu is open, it navigates through the menu items. If pressed at the last visible option, it scrolls to the next "hidden" menu item.
Up arrowWhen the focus is placed on the component that contains the menu, it opens the menu. When the menu is open, it navigates through menu options.
EnterIt opens and closes the menu. When the focus is on an item within the menu, it selects that item.
EscIt closes the menu when it is open.
HomeOptionally, it moves the focus to the first item within the menu. Optionally, in a single-select list box, selection may also move with focus. Supporting this key is strongly recommended for lists with more than five options.
EndOptionally, it moves the focus to the last option. Optionally, in a single-select listbox, selection may also move with focus. Supporting this key is strongly recommended for lists with more than five options.

Demos

Simple menu with input

NameValue
View
Reading direction

With custom menu item display

Use the footer prop to add a special menu item that will appear at the end of the menu. When scrolling is enabled, the footer item is pinned to the bottom of the menu (see the next demo). The footer item can be customized via the default slot, just like regular menu items.

See the TypeaheadSearch demos for a real-world example.

With scrolling enabled

In the Menu component, all menu items will be shown by default and the height of the menu will grow to accommodate the menu items. To limit the number of menu items shown at once and enable scrolling within the menu, set the visibleItemLimit prop to a positive number.

Although the default behavior in the Menu component is to show all menu items, some components that use the Menu component have a default visibleItemLimit prop set.

This demo includes a footer item, which is "sticky" to the bottom of the menu.

With no results message

If the no-results slot is populated, the Menu component will automatically display it when there are zero menu items.

Pending state

Pending state indicators can be displayed to indicate that menu items are being fetched. Set the pending prop to true to show the inline progress bar and "pending" message, which can be populated via the pending slot. See TypeaheadSearch for a real-world implementation of this.

When there are no menu items (e.g. on an initial search), the inline progress bar and the "pending" message will display.

When there are menu items, only the inline progress bar will display.

With multiselect

To enable multiple selections, set the selected prop to an array: an empty array when there are no selections, and an array of the selected menu items' values when there are selections.

Vue usage

WARNING

This is not a standalone component. It's intended for use inside other components, mainly within Codex. For example, the Select, Lookup and MenuButton components use this component internally.

Designed for use in components, like Select, Lookup and MenuButton, that display a menu below another element (for example, a text input). This component renders a list of items, manages which item is selected, highlighted, and active, and handles keyboard navigation. It does not display the selected item or manage an input; the parent component needs to do that.

Components using a menu should use the useFloatingMenu composable to ensure the menu is positioned correctly relative to the input (or other triggering element). The useFloatingMenu composable also manages the rounded corners on the Menu; if you are not using the useFloatingMenu composable, you will have to do this yourself, by setting border-top-left-radius and border-top-right-radius to border-radius-sharp token.

The selected and expanded props must be bound with v-model, even if the parent component doesn't use them. Without these v-model bindings, the menu won't function correctly.

The menu itself is not focusable; for keyboard navigation to work, the parent component needs to provide a focusable element, listen for keydown events on that element, and pass those events to the menu by calling the delegateKeyNavigation method.

For accessibility support, the parent component must set the following attributes on the focusable element:

  • role="combobox"
  • aria-controls, set to the ID of the menu
  • aria-expanded, set to "true" when the menu is expanded and to "false" when it's closed (the useGeneratedId composable can be used to assign an ID to the menu)
  • aria-activedescendant, set to the ID of the highlighted menu item (use the .id property of the object returned by the getHighlightedMenuItem method)
  • If the menu's items change in response to the user typing in a text input, aria-autocomplete should be set to the appropriate value. See MDN for documentation on which value to set for this attribute.

Props

Prop nameDescriptionTypeDefault
menuItems(required)Menu items. See the MenuItemData type.MenuItemData[]
footerInteractive footer item.

This is a special menu item which is pinned to the bottom of the menu. When scrolling is enabled within the menu, the footer item will always be visible at the bottom of the menu. When scrolling is not enabled, the footer item will simply appear as the last menu item.

The footer item is selectable, like other menu items.
MenuItemDatanull
selected(required)Value(s) of the selected menu item(s). A single value for single-select, or an array of values for multi-select.

Must be bound with v-model:selected.

The property should be initialized to null (for single-select) or an empty array (for multi-select) rather than using a falsy value.
MenuItemValue|MenuItemValue[]|null
expanded(required)Whether the menu is expanded. Must be bound with v-model:expanded.boolean
showPendingWhether to display pending state indicators. Meant to indicate that new menu items are being fetched or computed.

When true, the menu will expand if not already expanded, and an inline progress bar will display. If there are no menu items yet, a message can be displayed in the pending slot, e.g. "Loading results".
booleanfalse
visibleItemLimitLimit the number of menu items to display before scrolling.

Setting this prop to anything falsy will show all menu items.

By default, all menu items are shown.
number|nullnull
showThumbnailWhether menu item thumbnails (or a placeholder icon) should be displayed.booleanfalse
boldLabelWhether to bold menu item labels.booleanfalse
hideDescriptionOverflowWhether to hide description text overflow via an ellipsis.booleanfalse
searchQueryThe search query to be highlighted within the menu items' titles.string''
showNoResultsSlotWhether to show the no-results slot content.

The Menu component automatically shows this slot when there is content in the no-results slot and there are zero menu items. However, some components may need to customize this behavior, e.g. to show the slot even when there is at least one menu item. This prop can be used to override the default Menu behavior.

Possible values: null (default): the no-results slot will display only if there are zero menu items. true: the no-results slot will display, regardless of number of menu items. false: the no-results slot will not display, regardless of number of menu items.
boolean|nullnull

Methods

Method nameDescriptionSignature
isExpandedReturns whether the menu is expanded.Returns: boolean
getHighlightedMenuItemGet the highlighted menu item, if any.

The parent component should set aria-activedescendant to the .id property of the object returned by this method. If this method returns null, aria-activedescendant should not be set.
Returns: MenuItemDataWithId|null The highlighted menu item, or null if no item is highlighted or if the menu is closed.
getHighlightedViaKeyboardGet whether the last highlighted item was highlighted via the keyboard.Returns: boolean Whether the last highlighted menu item was highlighted via keyboard.
clearActiveEnsure no menu item is active. This unsets the active item if there is one.Returns: void
delegateKeyNavigationHandles all necessary keyboard navigation.

The parent component should listen for keydown events on its focusable element, and pass those events to this method. Events for arrow keys, tab and enter are handled by this method. If a different key was pressed, this method will return false to indicate that it didn't handle the event.
Params:
  • event KeyboardEvent - Keydown event object
Returns: boolean Whether the event was handled

Events

Event namePropertiesDescription
menu-item-clickmenuItem MenuItemDataWithId - The menu item that was clickedWhen a menu item is clicked.

Typically, components with menus will respond to the selected value change, but occasionally, a component might want to react specifically when a menu item is clicked.
update:selectedselectedValue MenuItemValue|MenuItemValue[]|null - selected value or valuesWhen the selected menu item changes.

Property will be a single value or null in single-select mode, or an array of values or an empty array in multiselect mode.
update:expandednewValue boolean - The new expanded state (true for open, false for closed)When the menu opens or closes.
menu-item-keyboard-navigationhighlightedMenuItem MenuItemDataWithId - The menu itemWhen a menu item is highlighted via keyboard navigation.
load-moreWhen the user scrolls towards the bottom of the menu.

If it is possible to add or load more menu items, then now would be a good moment so that the user can experience infinite scrolling.

Slots

NameDescriptionBindings
pendingMessage to indicate pending state.
no-resultsMessage to show if there are no menu items to display.
defaultDisplay of an individual item in the menu
active boolean - Whether the current item is visually active