Menu
A menu displays a list of actions or options that a user can choose.
import {MenuTrigger, Menu, Popover, SubmenuTrigger, MenuSection, Separator} from 'react-aria-components';
import {Button} from './Button';
import {MenuItem} from './Menu';
<MenuTrigger>
<Button aria-label="Actions">☰</Button>
<Popover>
<Menu>
<MenuItem onAction={() => alert('open')}>Open</MenuItem>
<MenuItem onAction={() => alert('rename')}>Rename…</MenuItem>
<MenuItem onAction={() => alert('duplicate')}>Duplicate</MenuItem>
<MenuItem onAction={() => alert('share')}>Share…</MenuItem>
<SubmenuTrigger>
<MenuItem>Share</MenuItem>
<Popover>
<Menu>
<MenuItem>Email</MenuItem>
<MenuItem>SMS</MenuItem>
<MenuItem>Instagram</MenuItem>
</Menu>
</Popover>
</SubmenuTrigger>
<MenuItem onAction={() => alert('delete')}>Delete…</MenuItem>
<Separator />
<MenuSection selectionMode="multiple" defaultSelectedKeys={['files']}>
<MenuItem id="files">Show files</MenuItem>
<MenuItem id="folders">Show folders</MenuItem>
</MenuSection>
</Menu>
</Popover>
</MenuTrigger>
Content
Menu
follows the Collection Components API, accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the items
prop, and a function to render the children.
import {MenuTrigger, Menu, MenuItem, Button, Popover} from 'react-aria-components';
function Example() {
let items = [
{ id: 1, name: 'New file…' },
{ id: 2, name: 'New window' },
{ id: 3, name: 'Open…' },
{ id: 4, name: 'Save' },
{ id: 5, name: 'Save as…' },
{ id: 6, name: 'Revert file' },
{ id: 7, name: 'Print…' },
{ id: 8, name: 'Close window' },
{ id: 9, name: 'Quit' }
];
return (
<MenuTrigger>
<Button>File</Button>
<Popover>
<Menu items={items}>
{(item) => <MenuItem>{item.name}</MenuItem>}
</Menu>
</Popover>
</MenuTrigger>
);
}
Text slots
Use the "label"
and "description"
slots to separate primary and secondary content within a <MenuItem>
. This improves screen reader announcements and can also be used for styling purposes. Use the <Keyboard>
component to display a keyboard shortcut.
import {MenuTrigger, Menu, MenuItem, Text, Keyboard, Button, Popover} from 'react-aria-components';
<MenuTrigger>
<Button>Permissions</Button>
<Popover>
<Menu>
<MenuItem textValue="Copy">
<Text slot="label">Copy</Text>
<Text slot="description">Copy the selected text</Text>
<Keyboard>⌘C</Keyboard>
</MenuItem>
<MenuItem textValue="Cut">
<Text slot="label">Cut</Text>
<Text slot="description">Cut the selected text</Text>
<Keyboard>⌘X</Keyboard>
</MenuItem>
<MenuItem textValue="Paste">
<Text slot="label">Paste</Text>
<Text slot="description">Paste the copied text</Text>
<Keyboard>⌘V</Keyboard>
</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
Sections
Use the <MenuSection>
component to group options. A <Header>
element may also be included to label the section. Sections without a header must have an aria-label
.
import {MenuTrigger, Menu, MenuItem, MenuSection, Header, Button, Popover} from 'react-aria-components';
<MenuTrigger>
<Button>Publish</Button>
<Popover>
<Menu>
<MenuSection>
<Header>Export</Header>
<MenuItem>Image…</MenuItem>
<MenuItem>Video…</MenuItem>
<MenuItem>Text…</MenuItem>
</MenuSection>
<MenuSection>
<Header>Share</Header>
<MenuItem>YouTube…</MenuItem>
<MenuItem>Instagram…</MenuItem>
<MenuItem>Email…</MenuItem>
</MenuSection>
</Menu>
</Popover>
</MenuTrigger>
Submenus
Wrap a <MenuItem>
and a <Popover>
with a <SubmenuTrigger>
to create a submenu.
import {MenuTrigger, Menu, Popover, SubmenuTrigger, Button, Popover} from 'react-aria-components';
import {MenuItem} from './Menu';
<MenuTrigger>
<Button>Actions</Button>
<Popover>
<Menu>
<MenuItem>Cut</MenuItem>
<MenuItem>Copy</MenuItem>
<MenuItem>Delete</MenuItem>
<SubmenuTrigger>
<MenuItem>Share</MenuItem>
<Menu>
<MenuItem>SMS</MenuItem>
<MenuItem>Instagram</MenuItem>
<SubmenuTrigger>
<MenuItem>Email</MenuItem>
<Popover>
<Menu>
<MenuItem>Work</MenuItem>
<MenuItem>Personal</MenuItem>
</Menu>
</Popover>
</SubmenuTrigger>
</Menu>
</SubmenuTrigger>
</Menu>
</Popover>
</MenuTrigger>
Separators
Separators may be added between menu items or sections in order to create non-labeled groupings.
import {MenuTrigger, Menu, MenuItem, Separator, Button, Popover} from 'react-aria-components';
<MenuTrigger>
<Button>Actions</Button>
<Popover>
<Menu>
<MenuItem>New…</MenuItem>
<MenuItem>Open…</MenuItem>
<Separator />
<MenuItem>Save</MenuItem>
<MenuItem>Save as…</MenuItem>
<MenuItem>Rename…</MenuItem>
<Separator />
<MenuItem>Page setup…</MenuItem>
<MenuItem>Print…</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
Links
Use the href
prop on a <MenuItem>
to create a link. See the client side routing guide to learn how to integrate with your framework.
import {MenuTrigger, Menu, MenuItem, Button, Popover} from 'react-aria-components';
<MenuTrigger>
<Button>Links</Button>
<Popover>
<Menu>
<MenuItem href="https://adobe.com/" target="_blank">Adobe</MenuItem>
<MenuItem href="https://apple.com/" target="_blank">Apple</MenuItem>
<MenuItem href="https://google.com/" target="_blank">Google</MenuItem>
<MenuItem href="https://microsoft.com/" target="_blank">Microsoft</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
Autocomplete
Popovers can include additional components as siblings of a menu. This example uses an Autocomplete with a SearchField to let the user filter the items.
import {Autocomplete, useFilter} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem} from './Menu';
import {Button} from './Button';
import {Popover} from './Popover';
import {SearchField} from './SearchField';
function Example() {
let {contains} = useFilter({sensitivity: 'base'});
return (
<MenuTrigger>
<Button>Add tag...</Button>
<Popover>
<Autocomplete filter={contains}>
<SearchField label="Search tags" autoFocus />
<Menu>
<MenuItem>News</MenuItem>
<MenuItem>Travel</MenuItem>
<MenuItem>Shopping</MenuItem>
<MenuItem>Business</MenuItem>
<MenuItem>Entertainment</MenuItem>
<MenuItem>Food</MenuItem>
<MenuItem>Technology</MenuItem>
<MenuItem>Health</MenuItem>
<MenuItem>Science</MenuItem>
</Menu>
</Autocomplete>
</Popover>
</MenuTrigger>
);
}
Selection
Use the selectionMode
prop to enable single or multiple selection. The selected items can be controlled via the selectedKeys
prop, matching the id
prop of the items. Items can be disabled with the isDisabled
prop. See the selection guide for more details.
Current selection: rulers
Section-level selection
Each section in a menu may have independent selection states by passing selectionMode
and selectedKeys
to the MenuSection
.
import type {Selection} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem, MenuSection, Header, Button, Popover} from 'react-aria-components';
import {useState} from 'react';
function Example() {
let [style, setStyle] = useState<Selection>(new Set(['bold']));
let [align, setAlign] = useState<Selection>(new Set(['left']));
return (
<MenuTrigger>
<Button>Edit</Button>
<Popover>
<Menu>
<MenuSection>
<Header>Clipboard</Header>
<MenuItem>Cut</MenuItem>
<MenuItem>Copy</MenuItem>
<MenuItem>Paste</MenuItem>
</MenuSection>
<MenuSection
selectionMode="multiple"
selectedKeys={style}
onSelectionChange={setStyle}>
<Header>Text style</Header>
<MenuItem id="bold">Bold</MenuItem>
<MenuItem id="italic">Italic</MenuItem>
<MenuItem id="underline">Underline</MenuItem>
</MenuSection>
<MenuSection selectionMode="single" selectedKeys={align} onSelectionChange={setAlign}>
<Header>Text alignment</Header>
<MenuItem id="left">Left</MenuItem>
<MenuItem id="center">Center</MenuItem>
<MenuItem id="right">Right</MenuItem>
</MenuSection>
</Menu>
</Popover>
</MenuTrigger>
);
}
Menu trigger
Custom trigger
MenuTrigger
works with any pressable React Aria component (e.g. Button, Link, etc.). Use the <Pressable>
component or usePress hook to wrap a custom trigger element such as a third party component or DOM element.
import {MenuTrigger, Menu, MenuItem, Button, Popover, Pressable} from 'react-aria-components';
<MenuTrigger>
<Pressable>
<span role="button">Custom trigger</span>
</Pressable>
<Popover>
<Menu>
<MenuItem>Open</MenuItem>
<MenuItem>Rename…</MenuItem>
<MenuItem>Duplicate</MenuItem>
<MenuItem>Delete…</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
const CustomTrigger = React.forwardRef((props, ref) => (
<button {...props} ref={ref} />
));
Long press
Use trigger="longPress"
to open the menu on long press instead of on click/tap. Keyboard users can open the menu using Alt ▼. This is useful when the menu trigger has a primary action on press, and the menu provides secondary actions.
import {MenuTrigger, Menu, MenuItem, Button, Popover} from 'react-aria-components';
<MenuTrigger trigger="longPress">
<Button onPress={() => alert('crop')}>Crop ▼</Button>
<Popover>
<Menu>
<MenuItem>Rotate</MenuItem>
<MenuItem>Slice</MenuItem>
<MenuItem>Clone stamp</MenuItem>
</Menu>
</Popover>
</MenuTrigger>