Skip to contentSkip to navigationSkip to topbar
Paste assistant Assistant
Figma
Star

Menu

Version 14.1.3GithubStorybookPeer review pending

A Menu is a button that presents a list of items that users can choose to trigger an action.

Component preview theme
const MenuExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="primary">
Actions you can take <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Actions">
<MenuItem {...menu}>Call your representatives</MenuItem>
<MenuItem {...menu}>Support black-owned businesses</MenuItem>
<MenuItem {...menu}>Vote in national, state, and local elections</MenuItem>
</Menu>
</>
);
};
render(
<MenuExample />
)

Guidelines

Guidelines page anchor

About Menu

About Menu page anchor

A menu presents a list of menu items that a user can choose to perform an action with. This component includes a menu trigger (a button in our case) and a menu comprising of menu items that are shown upon actioning the trigger. A menu item can be used to perform an action, a page navigation or show a sub menu.

Each menu item can only perform a single action.

(warning)

Do not nest multiple actions within a menu item

Please do not add additional actionable elements inside a menu item. They will not be keyboard accessible.

When the user is focused on a menu trigger, the following keyboard interactions apply:

  • Enter and space open the menu and select the current menu item
  • Up and down arrows move the user between the menu items
    • Disabled menu items, separators, and group labels are never focused
Component preview theme
const MenuExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="primary">
Actions you can take <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Actions">
<MenuItem {...menu}>Call your representatives</MenuItem>
<MenuItem {...menu}>Support black-owned businesses</MenuItem>
<MenuItem {...menu}>Vote in national, state, and local elections</MenuItem>
</Menu>
</>
);
};
render(
<MenuExample />
)

Use MenuGroups to create hierarchy or logical groupings within longer menus. MenuGroups have a visible group label that should describe the grouping clearly. They can be given a prefix icon; please only use icons in a decorative manner and make the label descriptive standalone.

Add separators between MenuGroups and other menu items.

Component preview theme
const MenuGroupExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="primary">
Cool places <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Actions">
<MenuGroup label="Social media" icon={<AttachIcon decorative />}>
<MenuItem {...menu}>Twitter</MenuItem>
<MenuItem {...menu}>Myspace</MenuItem>
<MenuItem {...menu}>Dribbble</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuGroup label="Search engines">
<MenuItem {...menu}>Ecosia</MenuItem>
<MenuItem {...menu}>DuckDuckGo</MenuItem>
</MenuGroup>
</Menu>
</>
);
};
render(
<MenuGroupExample />
)
Component preview theme
const PreferencesMenu = React.forwardRef((props, ref) => {
const menu = useMenuState();
return (
<>
<SubMenuButton ref={ref} {...menu} {...props}>
Preferences
</SubMenuButton>
<Menu {...menu} aria-label="Preferences">
<MenuItem {...menu}>Settings</MenuItem>
<MenuItem {...menu} disabled>
Extensions
</MenuItem>
<MenuSeparator {...menu} />
<MenuItem {...menu}>Keyboard shortcuts</MenuItem>
</Menu>
</>
);
});
const SubMenu = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="secondary">
Code <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Code">
<MenuItem {...menu}>About Visual Studio Code</MenuItem>
<MenuItem {...menu}>Check for Updates...</MenuItem>
<MenuSeparator {...menu} />
<MenuItem {...menu} as={PreferencesMenu} />
</Menu>
</>
);
};
render(
<SubMenu />
)

The MenuButton is the standard Paste Button with some extra functionality. As a result it takes all the usual props the Paste Button takes, meaning you have full access to all the variants and styling options.

For example, you can create an icon button menu trigger like so:

Component preview theme
const IconExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="reset" size="reset">
<MoreIcon decorative={false} title="More options" />
</MenuButton>
<Menu {...menu} aria-label="Preferences">
<MenuItem {...menu}>Settings</MenuItem>
<MenuItem {...menu} disabled>
Extensions
</MenuItem>
<MenuSeparator {...menu} />
<MenuItem {...menu}>Keyboard shortcuts</MenuItem>
</Menu>
</>
);
};
render(
<IconExample />
)

Menu items come with the ability to be selected, in the same way as a checkbox or radio button. This is useful when a user is asked to perform a persistent action, where the selection should be preserved for future reference. Selections can either be single, or multiple, just like radio and checkboxes.

Single select menu items

Single select menu items page anchor
Component preview theme
const RadioMenu = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="secondary">
Display view <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Display view">
<MenuItemRadio {...menu} name="display-view" value="grid">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<DataTableIcon decorative={true} /> Data grid
</Box>
</MenuItemRadio>
<MenuItemRadio {...menu} name="display-view" value="bar">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<DataBarChartIcon decorative={true} /> Bar chart
</Box>
</MenuItemRadio>
<MenuItemRadio {...menu} name="display-view" value="line">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<DataLineChartIcon decorative={true} /> Line chart
</Box>
</MenuItemRadio>
<MenuItemRadio {...menu} name="display-view" disabled value="pie">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<DataPieChartIcon decorative={true} /> Pie chart
</Box>
</MenuItemRadio>
<MenuSeparator {...menu} />
<MenuItemRadio {...menu} name="display-view" value="list">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<UnorderedListIcon decorative={true} /> List
</Box>
</MenuItemRadio>
</Menu>
</>
);
};
render(
<RadioMenu />
)
Component preview theme
const CheckboxMenu = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="secondary">
Text formatting <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Display view">
<MenuItemCheckbox {...menu} name="display-view" value="bold">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<BoldIcon decorative={true} /> Bold
</Box>
</MenuItemCheckbox>
<MenuItemCheckbox {...menu} name="display-view" value="underlined">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<UnderlineIcon decorative={true} /> Underlined
</Box>
</MenuItemCheckbox>
<MenuItemCheckbox {...menu} name="display-view" value="italic">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<ItalicIcon decorative={true} /> Italic
</Box>
</MenuItemCheckbox>
<MenuSeparator {...menu} />
<MenuItemCheckbox {...menu} name="display-view" value="strike">
<Box as="span" display="flex" columnGap="space30" alignItems="center">
<StrikethroughIcon decorative={true} /> Strike
</Box>
</MenuItemCheckbox>
</Menu>
</>
);
};
render(
<CheckboxMenu />
)

Paste provides a few composed variants of the Menu component. These compositions are designed to help you build menus for common scenarios and use cases.

Using a Badge to contain a menu trigger can be useful when you want display a dynamic identifier. A example use case might be an account, or availability of an agent.

The <MenuBadge /> accepts all the variants that a badge does: neutral, success, warning, error, new, subaccount, decorative10, decorative20, decorative30, decorative40, neutral_counter, error_counter

Component preview theme
const MenuBadgeExample = () => {
const [account, setAccount] = React.useState('Account name');
const menu = useMenuState();
const onClick = (newAccount) => {
menu.hide();
setAccount(newAccount);
};
return (
<>
<MenuBadge {...menu} i18nButtonLabel="Change account" variant="decorative10">
{account}
</MenuBadge>
<Menu {...menu} aria-label="Accounts">
<MenuItem {...menu} onClick={()=>onClick('Account one')}>
Account one
</MenuItem>
<MenuItem {...menu} onClick={()=>onClick('Account two')}>
Account two
</MenuItem>
<MenuItem {...menu} onClick={()=>onClick('Account three')}>
Account three
</MenuItem>
</Menu>
</>
);
};
render(
<MenuBadgeExample />
)

A menu item can perform 2 basic tasks:

  • trigger an action (switching a view between grid and list)
  • trigger a page navigation (going to a new page)

To do so, either set href with a valid url to go to a new page, or set the onClick as an event handler on the MenuItem.

Component preview theme
const ActionsExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="secondary">
Actions <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Preferences">
<MenuItem
{...menu}
onClick={e => {
menu.hide();
alert('do something');
}}
>
Perform Action
</MenuItem>
<MenuItem {...menu} href="https://paste.twilio.design">Go to new page</MenuItem>
</Menu>
</>
);
};
render(
<ActionsExample />
)

Menu item labels should be concise, usually fewer than 20 characters.

Use words that are familiar to users so it's immediately clear what the menu item does.

Each menu item should be constructed similarly so they are "parallel." For example, the menu items "Edit" and "Copy" are parallel.

Use the variant prop in MenuItem to use a default or destructive item.

Component preview theme
const ItemsExample = () => {
const menu = useMenuState();
return (
<>
<MenuButton {...menu} variant="primary">
Menu item content <ChevronDownIcon decorative />
</MenuButton>
<Menu {...menu} aria-label="Preferences">
<MenuItem {...menu}>
Default item
</MenuItem>
<MenuItem variant="destructive" {...menu}>
Destructive item
</MenuItem>
<MenuItem {...menu}>
<MediaObject verticalAlign="center">
<MediaFigure spacing="space20">
<AttachIcon decorative={false} title="information" />
</MediaFigure>
<MediaBody>With left icon</MediaBody>
</MediaObject>
</MenuItem>
<MenuItem {...menu}>
<MediaObject verticalAlign="center">
<MediaBody>With right icon</MediaBody>
<MediaFigure spacing="space20" align="end">
<AttachIcon decorative={false} title="information" />
</MediaFigure>
</MediaObject>
</MenuItem>
<MenuItem {...menu}>
<MediaObject verticalAlign="center">
<MediaFigure spacing="space20">
<AttachIcon decorative={false} title="information" />
</MediaFigure>
<MediaBody>With two icons</MediaBody>
<MediaFigure spacing="space20" align="end">
<AttachIcon decorative={false} title="information" />
</MediaFigure>
</MediaObject>
</MenuItem>
<MenuItem {...menu}>
<MediaObject verticalAlign="center">
<MediaFigure spacing="space20">
<AttachIcon decorative={false} title="information" />
</MediaFigure>
<MediaBody>Keyboard shortcut?</MediaBody>
<MediaFigure spacing="space20" align="end">
<Text as="span" color="colorTextWeak" fontSize="fontSize20">
⌘+s
</Text>
</MediaFigure>
</MediaObject>
</MenuItem>
</Menu>
</>
);
};
render(
<ItemsExample />
)