MenuTrigger
The MenuTrigger serves as a wrapper around a Menu and its associated trigger, linking the Menu's open state with the trigger's press state.
| install | yarn add @react-spectrum/menu |
|---|---|
| version | 3.0.0-alpha.1 |
| usage | import {MenuTrigger} from '@react-spectrum/menu' |
Example#
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Content#
The MenuTrigger accepts exactly two children: the Menu and the element which triggers the opening of the Menu. The trigger must be the first child passed into the MenuTrigger and should be an element that supports press events.
If the Menu is open it will close on blur or scroll events.
The defaultSelectedKeys prop can be used to set the default state of the Menu
(uncontrolled). Alternatively, the selectedKeys prop can be used to make the
selected state of the Menu controlled.
<MenuTrigger>
<ActionButton>
Menu Button Controlled
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name" selectedKeys=['Kangaroo']>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
Menu Button Uncontrolled
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name" defaultSelectedKeys=['Kangaroo']>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>The selectionMode prop can be used to switch from the default selection of a single menu item to multiple menu items or none.
function Example() {
let [state setState] = ReactuseState(['Kangaroo' 'Snake']);
let onAction = (value) => {
if (stateincludes(value)) {
setState(statefilter((item) => item !== value));
} else {
let curState = state;
curStatepush(value);
setState(curState);
}
};
return (
<div>
<MenuTrigger>
<ActionButton>
Menu Button Multiple
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
onAction=onAction
defaultSelectedKeys=state
selectionMode="multiple">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
Menu Button None
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="none">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
</div>
);
}Sections#
Menu's may have Sections with titles and children items.
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Section 1' children: [{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]} {name: 'Section 2' children: [{name: 'Koala'}]}] itemKey="name">
item => (
<Section items=itemchildren title=itemname>
item => <Item>itemname</Item>
</Section>
)
</Menu>
</MenuTrigger>Sematic Elements#
A Menu item's content may be any renderable node, not just strings.
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu
itemKey="name"
items=[
{name: 'Copy' icon: 'Copy' shortcut: '⌘C'}
{name: 'Cut' icon: 'Cut' shortcut: '⌘X'}
{name: 'Paste' icon: 'Paste' shortcut: '⌘V'}
]>
item => {
let iconMap = {
Copy
Cut
Paste
};
let Icon = iconMap[itemicon];
return (
<Item childItems=itemchildren textValue=itemname>
<Icon size="S" />
<Text>itemname</Text>
<Keyboard>itemshortcut</Keyboard>
</Item>
);
}
</Menu>
</MenuTrigger>Accessibility#
The MenuTrigger uses the prop aria-controls to point at the menu, which uses
the prop aria-labelledby to reference the trigger. Other aria props of the
MenuTrigger are aria-haspopup and aria-expanded.
Menu sections without labels use the prop aria-label.
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Section 1' children: [{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]} {name: 'Section 2' children: [{name: 'Koala'}]}] itemKey="name">
item => (
<Section items=itemchildren aria-label=itemname>
item => <Item>itemname</Item>
</Section>
)
</Menu>
</MenuTrigger>Events#
MenuTrigger accepts an onOpenChange handler which is triggered whenever the Menu is opened or closed.
The example below uses onOpenChange to update a separate span element with the current open state of the Menu.
function Example() {
let [state setState] = ReactuseState(false);
return (
<div>
<MenuTrigger onOpenChange=(isOpen) => setState(isOpen)>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<span style={'margin-left': '8px'}>Current open state: statetoString()</span>
</div>
);
}Menu accepts an onAction handler which is triggered whenever a Menu item is selected.
The example below uses onAction to tell the user which Menu item was selected.
function Example() {
let onAction = (value) => alert('Menu item selected: ' + value);
return (
<div>
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name" onAction=onAction>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
</div>
);
}Props#
MenuTrigger#
| Name | Type | Default | Description |
children | ReactElement[] | — | The contents of the MenuTrigger, a trigger and a Menu. See the MenuTrigger Content section for more information on what to provide as children. |
align | Alignment | — | Where the Menu aligns with it's trigger. |
direction | 'bottom' | 'top' | — | Where the Menu opens relative to it's trigger. |
closeOnSelect | boolean | — | Whether the Menu closes when a selection is made. |
isOpen | boolean | — | Whether the Menu loads open (controlled). |
defaultOpen | boolean | — | Whether the Menu loads open (uncontrolled). |
shouldFlip | boolean | — | Whether the element should flip its orientation when there is insufficient room for it to render completely. |
Events
| Name | Type | Default | Description |
onOpenChange | (isOpen: boolean) => void | — | Handler that is called when the Menu opens or closes. |
Menu#
| Name | Type | Default | Description |
Visual Options#
Align and Direction#
<MenuTrigger align="start" direction="bottom">
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="start" direction="top">
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="end" direction="bottom">
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="end" direction="top">
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Autofocus#
Applying autoFocus to the Menu of the MenuTrigger sets focus to the Menu upon opening.
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Button Autofocus
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
autoFocus>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Button Autofocus Last
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
autoFocus="last">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Closes Menu onSelect#
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Disabled Trigger#
<MenuTrigger>
<ActionButton isDisabled>
Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Disabled Menu Items#
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
disabledKeys=['Aardvark' 'Snake']>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
Menu Button
</ActionButton>
<Menu
items=[{name: 'Aardvark' key: 1} {name: 'Kangaroo' key: 2} {name: 'Snake' key: 3}]
itemKey="name"
disabledKeys=['1' '3']>
item => <Item key=itemkey>itemname</Item>
</Menu>
</MenuTrigger>Flipping#
Applying shouldFlip to the MenuTrigger makes the Menu attempt to flip on its
main axis in situations where the original placement would cause it to render out of view.
<MenuTrigger shouldFlip>
<ActionButton>
Menu Button shouldFlip
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger shouldFlip=false>
<ActionButton>
Menu Button shouldFlip=false
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Open#
The isOpen and defaultOpen props control whether the MenuTrigger is open by default.
They apply controlled and uncontrolled behavior on the MenuTrigger respectively.