Menu

A list of actions for a row or item, opened from a trigger.

Live React portVue source: WildMenu.vueStorybook story: Navigation/MenuReact component: WMenu

Try it

Pick an action, then open the menu again from the keyboard and use the arrow keys.

Nothing picked yet
Trigger
Align
Min width
Descriptions
Divider
Disable one
Close on select
const items = [
  { id: 'view', label: 'View events' },
  { id: 'config', label: 'Configure sensors' },
  { id: 'graph', label: 'View graph', divider: true },
  { id: 'delete', label: 'Delete site', variant: 'destructive' },
]

<WildMenu :items="items" @select="run">
  <template #trigger="{ toggle }">
    <WildButton variant="borders" size="sm" icon="chevron-down" @click="toggle">Actions</WildButton>
  </template>
</WildMenu>

When to use

  • Use it for actions on one record, such as a site row in a table.
  • Use it when the trigger is your own button, or actions need a description or a divider.
Don’t use it
  • To switch a view or choose a value. Use Dropdown.
  • For a kebab of plain actions with no descriptions or dividers. Use Icon menu.
  • For one or two actions that fit on the row. Use Button.

Dividers and descriptions

A divider closes a group of actions. Put the destructive action last, after a divider.

View events
Configure sensors
View graph
Delete site
grouped
View eventsOpens the event log
Configure sensorsOpens sensor settings
Delete site
descriptions, one disabled
// grouped
const items = [
  { id: 'view', label: 'View events' },
  { id: 'config', label: 'Configure sensors' },
  { id: 'graph', label: 'View graph', divider: true },
  { id: 'delete', label: 'Delete site', variant: 'destructive' },
]

// descriptions, one disabled
const items = [
  { id: 'view', label: 'View events', description: 'Opens the event log' },
  { id: 'config', label: 'Configure sensors', description: 'Opens sensor settings', disabled: true, divider: true },
  { id: 'delete', label: 'Delete site', variant: 'destructive' },
]
Both menus end on a divider and the destructive action. A disabled action keeps its place, so the list doesn’t shift.

Content

  • Start each action with a verb, and name the object: View events, Delete site.
  • Use sentence case, and keep labels to one line.
  • Add a description only when the label can’t say what happens, and put the consequence there.
  • Confirm a destructive action with a confirm dialog.

Accessibility

The trigger announces a menu and whether it’s open. An icon trigger needs an aria-label that names the record.

KeyWhat it does
Enter / SpaceOn the trigger, opens on the first action. In the menu, runs the action.
Down / UpOn the trigger, opens on the first or last action. In the menu, moves and wraps.
Home / EndMoves to the first or last action.
A letterMoves to the next action starting with it.
EscapeCloses the menu and returns focus to the trigger.
TabCloses the menu and moves on.

Props

PropTypeDefaultDescription
itemsMenuItem[][]The actions, in order.
align'start' | 'end''start'Trigger edge the menu aligns to.
placement'bottom' | 'top''bottom'Preferred side; flips when there isn’t room.
minWidthnumber200Narrowest width in px; grows to fit.
maxHeightnumber400Height in px past which it scrolls.
closeOnSelectbooleantrueCloses after an action is picked.
@select(item: MenuItem) => void—Fires with the picked item.
#triggerslot { toggle, open }—The button that opens the menu.
Item idstring—Identifies the action in @select.
Item labelstring—The action’s text.
Item iconstring—Icon name, shown before the label.
Item descriptionstring—A second line under the label.
Item disabledbooleanfalseBlocks the action; arrow keys skip it.
Item variant'default' | 'destructive''default'Destructive turns the action red.
Item dividerbooleanfalseA rule after this action.

Tokens

TokenValueWhere it lands
--global-neutral-grey-500#E6E6E6Menu border and dividers.
--shadow-dropdown0 4px 12px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04)Menu elevation.
--radius-lg8pxMenu corners.
--global-cool-grey-1200#24262BAction label.
--global-cool-grey-900#595E6AIcon and description.
--global-neutral-grey-300#F1F1F1Action hover.
--global-red-900#BC1C1CDestructive label.
--global-red-100#FEEBEBDestructive hover.
--global-neutral-grey-800#ADACB0Disabled label and icon.
--global-blue-1000#1877F2Keyboard focus ring.