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 preselect items in the Menu
placing it in an uncontrolled state. Alternatively, the selectedKeys preselect
items in the Menu placing it in a controlled state.
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Controlled
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single"
selectedKeys=['Kangaroo']>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Uncontrolled
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single"
defaultSelectedKeys=['Snake']>
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.
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Selection Multiple
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
defaultSelectedKeys=['Kangaroo' 'Snake']
selectionMode="multiple">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger closeOnSelect=false>
<ActionButton>
Menu Selection None
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="none">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Sections#
Menus 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.
import {Keyboard Text} from '@react-spectrum/typography';
<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#
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 its trigger. |
direction | 'bottom' | 'top' | — | Where the Menu opens relative to its 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 space for it to render within the view. |
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" shouldFlip=false>
<ActionButton>
align=start direction=bottom
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="start" direction="top" shouldFlip=false>
<ActionButton>
align=start direction=top
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="end" direction="bottom" shouldFlip=false>
<ActionButton>
align=end direction=bottom
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger align="end" direction="top" shouldFlip=false>
<ActionButton>
align=end direction=top
</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 within the Menu upon opening.
<MenuTrigger>
<ActionButton>
autofocus
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single"
selectedKeys=['Kangaroo']
autoFocus>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
autofocus=false
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single"
selectedKeys=['Kangaroo']
autoFocus=false>
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
autofocus=first
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
autoFocus="first">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger>
<ActionButton>
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>
<ActionButton>
closeOnSelect=true
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger closeOnSelect=false>
<ActionButton>
closeOnSelect=false
</ActionButton>
<Menu
items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
itemKey="name"
selectionMode="single">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Disabled Trigger#
<MenuTrigger>
<ActionButton isDisabled>
Disabled Menu Button
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>Disabled Menu Items#
<MenuTrigger>
<ActionButton>
Disabled Menu Items
</ActionButton>
<Menu
items=[{name: 'Aardvark' dataId: 'a1b2c3'} {name: 'Kangaroo' dataId: 'g5h1j9'} {name: 'Snake' dataId: 'p8k3i4'}]
itemKey="dataId"
disabledKeys=['a1b2c3' 'p8k3i4']>
item => <Item>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>
shouldFlip=true
</ActionButton>
<Menu items=[{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}] itemKey="name">
item => <Item>itemname</Item>
</Menu>
</MenuTrigger>
<MenuTrigger shouldFlip=false>
<ActionButton>
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.