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 />)
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.
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
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.
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 />)
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:
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.
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 />)
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
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
.
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.
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 />)