Overview
An <sp-menu>
is used for creating a menu list. The various elements inside a menu are given as <sp-menu-group>
, <sp-menu-item>
, or <sp-menu-divider>
. Often a <sp-menu>
element will appear in a <sp-popover>
element so that it displays as a toggling menu.
Usage
yarn add @spectrum-web-components/menu
Import the side effectful registration of <sp-menu>
, <sp-menu-group>
, <sp-menu-item>
, or <sp-menu-divider>
individually as follows:
import '@spectrum-web-components/menu/sp-menu.js';
import '@spectrum-web-components/menu/sp-menu-group.js';
import '@spectrum-web-components/menu/sp-menu-item.js';
import '@spectrum-web-components/menu/sp-menu-divider.js';
When looking to leverage the Menu
, MenuGroup
, MenuItem
, or MenuDivider
base classes as a type and/or for extension purposes, do so via:
import {
Menu,
MenuGroup,
MenuItem,
MenuDivider
} from '@spectrum-web-components/menu';
Anatomy
<sp-menu label="Selection type">
<sp-menu-item>
Deselect
</sp-menu-item>
<sp-menu-item>
Select inverse
</sp-menu-item>
<sp-menu-item>
Feather...
</sp-menu-item>
<sp-menu-item>
Select and mask...
</sp-menu-item>
<sp-menu-item>
Save selection
</sp-menu-item>
<sp-menu-item disabled>
Make work path
</sp-menu-item>
</sp-menu>
Popover menus
Often an <sp-menu>
element will be delivered inside of an <sp-popover>
element when displaying it above other content.
<sp-popover open style="position: relative" label="Selection type">
<sp-menu>
<sp-menu-item value="item-1">Deselect</sp-menu-item>
<sp-menu-item value="item-2">Select inverse</sp-menu-item>
<sp-menu-item value="item-3">Feather...</sp-menu-item>
<sp-menu-item value="item-4">Select and mask...</sp-menu-item>
<sp-menu-item value="item-5">Save selection</sp-menu-item>
<sp-menu-item value="item-6" disabled>Make work path</sp-menu-item>
</sp-menu>
</sp-popover>
Labels
To render accessibly, an <sp-menu>
element or its parent <sp-popover>
must have a label. For an accessible label that is visibly hidden, but can still be read by assistive technology, use the label
attribute.
<sp-tabs selected="sp-field-label" auto label="Label options">
<sp-tab value="sp-field-label">Menu with label</sp-tab>
<sp-tab-panel value="sp-field-label">```html demo
<sp-menu id="menu-label-attribute" label="Selection type"> <sp-menu-item>Deselect</sp-menu-item> <sp-menu-item>Select inverse</sp-menu-item> <sp-menu-item>Feather...</sp-menu-item> <sp-menu-item>Select and mask...</sp-menu-item> <sp-menu-divider></sp-menu-divider> <sp-menu-item>Save selection</sp-menu-item> <sp-menu-item disabled>Make work path</sp-menu-item> </sp-menu>
</sp-tab-panel>
<sp-tab value="label-attribute">Popover with label</sp-tab>
<sp-tab-panel value="label-attribute">
```html demo
<sp-popover open style="position: relative" label="Selection type:">
<sp-menu id="popover-label-attribute">
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item>Select inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save selection</sp-menu-item>
<sp-menu-item disabled>Make work path</sp-menu-item>
</sp-menu>
</sp-popover>
</sp-tab-panel> </sp-tabs>
Options
Sizes
<sp-tabs selected="m" auto label="Size attribute options">
<sp-tab value="s">Small</sp-tab>
<sp-tab-panel value="s">```html demo
<sp-menu id="menu-s" size="s" label="Selection type"> <sp-menu-item>Deselect</sp-menu-item> <sp-menu-item>Select inverse</sp-menu-item> <sp-menu-item>Feather...</sp-menu-item> <sp-menu-item>Select and mask...</sp-menu-item> <sp-menu-divider></sp-menu-divider> <sp-menu-item>Save selection</sp-menu-item> <sp-menu-item disabled>Make work path</sp-menu-item> </sp-menu>
<sp-popover open style="position: relative" label="Selection type:"> <sp-menu id="menu-s-popover" size="s"> <sp-menu-item>Deselect</sp-menu-item> <sp-menu-item>Select inverse</sp-menu-item> <sp-menu-item>Feather...</sp-menu-item> <sp-menu-item>Select and mask...</sp-menu-item> <sp-menu-divider></sp-menu-divider> <sp-menu-item>Save selection</sp-menu-item> <sp-menu-item disabled>Make work path</sp-menu-item> </sp-menu> </sp-popover>
</sp-tab-panel>
<sp-tab value="m">Medium</sp-tab>
<sp-tab-panel value="m">
```html demo
<sp-menu id="menu-m" size="m" label="Selection type">
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item>Select inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save selection</sp-menu-item>
<sp-menu-item disabled>Make work path</sp-menu-item>
</sp-menu>
<sp-popover open style="position: relative" label="Selection type:">
<sp-menu id="menu-m-popover" size="m">
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item>Select inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save selection</sp-menu-item>
<sp-menu-item disabled>Make work path</sp-menu-item>
</sp-menu>
</sp-popover>
</sp-tab-panel>
<sp-tab value="l">Large</sp-tab>
<sp-tab-panel value="l">```html demo
<sp-menu id="menu-l" size="l" label="Selection type"> <sp-menu-item>Deselect</sp-menu-item> <sp-menu-item>Select inverse</sp-menu-item> <sp-menu-item>Feather...</sp-menu-item> <sp-menu-item>Select and mask...</sp-menu-item> <sp-menu-divider></sp-menu-divider> <sp-menu-item>Save selection</sp-menu-item> <sp-menu-item disabled>Make work path</sp-menu-item> </sp-menu>
<sp-popover open style="position: relative" label="Selection type:"> <sp-menu id="menu-l-popover" size="l"> <sp-menu-item>Deselect</sp-menu-item> <sp-menu-item>Select inverse</sp-menu-item> <sp-menu-item>Feather...</sp-menu-item> <sp-menu-item>Select and mask...</sp-menu-item> <sp-menu-divider></sp-menu-divider> <sp-menu-item>Save selection</sp-menu-item> <sp-menu-item disabled>Make work path</sp-menu-item> </sp-menu> </sp-popover>
</sp-tab-panel>
<sp-tab value="xl">Extra Large</sp-tab>
<sp-tab-panel value="xl">
```html demo
<sp-menu id="menu-xl" size="xl" label="Selection type">
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item>Select inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save selection</sp-menu-item>
<sp-menu-item disabled>Make work path</sp-menu-item>
</sp-menu>
<sp-popover open style="position: relative" label="Selection type:">
<sp-menu id="menu-xl-popover" size="xl">
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item>Select inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save selection</sp-menu-item>
<sp-menu-item disabled>Make work path</sp-menu-item>
</sp-menu>
</sp-popover>
</sp-tab-panel> </sp-tabs>
Selection
The <sp-menu>
element can be instructed to maintain a selection via the selects
attribute. Depending on the chosen algorithm, the <sp-menu>
element will hold a value
property and manage the selected
state of its <sp-menu-item>
descendants.
- When
selects="single"
, the<sp-menu>
element will maintain one selected item after an initial selection is made. - When
selects
is set tomultiple
, the<sp-menu>
element will maintain zero or more selected items. - When
selects
is set toinherit
, the<sp-menu>
element will allow its<sp-menu-item>
children to participate in the selection of its nearest<sp-menu>
ancestor.
<sp-tabs selected="selects-single" auto label="Selects attribute">
<sp-tab value="selects-single">Single</sp-tab>
<sp-tab-panel value="selects-single">```html demo
The value of the <sp-menu>
element is:
<sp-menu label="Choose a shape" selects="single" onchange="this.previousElementSibling.querySelector('#single-value').textContent=this.value" > <sp-menu-item value="item-1">Square</sp-menu-item> <sp-menu-item value="item-2" selected>Triangle</sp-menu-item> <sp-menu-item value="item-3">Parallelogram</sp-menu-item> <sp-menu-item value="item-4">Star</sp-menu-item> <sp-menu-item value="item-5">Hexagon</sp-menu-item> <sp-menu-item value="item-6" disabled>Circle</sp-menu-item> </sp-menu>
</sp-tab-panel>
<sp-tab value="selects-multiple">Multiple</sp-tab>
<sp-tab-panel value="selects-multiple">
```html demo
<p>
The value of the `<sp-menu>` element is:
<span id="multiple-value">item-3,item-4</span>
</p>
<sp-menu
label="Choose some fruit"
selects="multiple"
onchange="this.previousElementSibling.querySelector('#multiple-value').textContent=this.value"
>
<sp-menu-item value="item-1">Apple</sp-menu-item>
<sp-menu-item value="item-2">Banana</sp-menu-item>
<sp-menu-item value="item-3" selected>Goji berry</sp-menu-item>
<sp-menu-item value="item-4" selected>Grapes</sp-menu-item>
<sp-menu-item value="item-5" disabled>Kumquat</sp-menu-item>
<sp-menu-item value="item-6">Orange</sp-menu-item>
</sp-menu>
</sp-tab-panel>
<sp-tab value="selects-inherit">Inherit</sp-tab>
<sp-tab-panel value="selects-inherit">```html demo
The value of the <sp-menu>
element is:
item-3 || item-4 || item-8 || item-11
<sp-menu label="Choose some groceries" selects="multiple" value-separator=" || " onchange="this.previousElementSibling.querySelector('#inherit-value').textContent=this.value" > <sp-menu label="Fruit" selects="inherit"> <sp-menu-item value="item-1">Apple</sp-menu-item> <sp-menu-item value="item-2">Banana</sp-menu-item> <sp-menu-item value="item-3" selected>Goji berry</sp-menu-item> <sp-menu-item value="item-4" selected>Grapes</sp-menu-item> <sp-menu-item value="item-5" disabled>Kumquat</sp-menu-item> <sp-menu-item value="item-6">Orange</sp-menu-item> </sp-menu> <sp-menu label="Vegetables" selects="inherit"> <sp-menu-item value="item-7">Carrot</sp-menu-item> <sp-menu-item value="item-8" selected>Garlic</sp-menu-item> <sp-menu-item value="item-9" disabled>Lettuce</sp-menu-item> <sp-menu-item value="item-10">Onion</sp-menu-item> <sp-menu-item value="item-11" selected>Potato</sp-menu-item> <sp-menu-item value="item-12">Tomato</sp-menu-item> </sp-menu> </sp-menu> ```
</sp-tab-panel> </sp-tabs>
Behaviors
"change" event
Regardless of whether or not <sp-menu>
carries a selection, when one of the <sp-menu-item>
children that it manages is activated, the <sp-menu>
element will dispatch a change
event. At dispatch time, even when a selection is not held due to the absence of the selects
attribute, the value
of the <sp-menu>
will correspond to the <sp-menu-item>
that was activated. When the selects
attribute is present, this value
will persist beyond the lifecycle of the change
event. When selects="multiple"
, the values of multiple items will be comma separated, unless otherwise set via the value-separator
attribute.
Note: The change
event is only dispatched on a left mouse click or Enter/Space keypress. Right/Middle mouse clicks will not dispatch the change
event.
Accessibility
Review the accessibility guidelines for the menu-item and menu-group descendants.
Include a label
A menu is required to have an accessible label.