HyMenu
Usage examples on this page are written for Lit / plain HTML (
<hy-menu>). The same component ships asHyMenuin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A role="menu" panel composed on top of hy-popover. Owns keyboard navigation (Arrow, Home/End, typeahead), roving tabindex, and submenu coordination. Items are slotted in the default slot and may be grouped with hy-menu-group or separated with hy-divider.
Trigger patterns
By id — pass for="<id>" referencing the trigger. Requires a manual click handler on the trigger to call menu.toggle().
Programmatic — call menu.show(anchor?) with an optional element. When an element is passed, the menu anchors to it (generating an id if the element doesn't already have one).
Composite triggers — hy-menu-button, hy-context-menu, and hy-menubar-item wrap hy-menu and handle trigger wiring themselves.
Examples
Menu attached to a trigger by id
<hy-button id="edit-trigger">Edit</hy-button>
<hy-menu for="edit-trigger">
<hy-menu-item value="cut" label="Cut" shortcut="⌘X"></hy-menu-item>
<hy-menu-item value="copy" label="Copy" shortcut="⌘C"></hy-menu-item>
<hy-menu-item value="paste" label="Paste" shortcut="⌘V"></hy-menu-item>
<hy-divider role="separator"></hy-divider>
<hy-menu-item value="delete" label="Delete" variant="danger"></hy-menu-item>
</hy-menu>
<script>
document.querySelector('hy-menu').addEventListener('select', (e) => {
console.log(e.detail.value);
});
</script>Grouped items with checkbox and radio rows
<hy-button id="view-trigger">View</hy-button>
<hy-menu for="view-trigger">
<hy-menu-group label="Panels">
<hy-menu-item-checkbox value="word-wrap" label="Word wrap" checked></hy-menu-item-checkbox>
<hy-menu-item-checkbox value="minimap" label="Minimap"></hy-menu-item-checkbox>
</hy-menu-group>
<hy-divider role="separator"></hy-divider>
<hy-menu-group label="Zoom" role="radiogroup">
<hy-menu-item-radio value="zoom-50" label="50%"></hy-menu-item-radio>
<hy-menu-item-radio value="zoom-100" label="100%" checked></hy-menu-item-radio>
<hy-menu-item-radio value="zoom-150" label="150%"></hy-menu-item-radio>
</hy-menu-group>
</hy-menu>API
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
open | open | boolean | false | Controlled open state. |
placement | placement | 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' | 'bottom-start' | Placement relative to anchor. |
distance | distance | number | 4 | Gap between anchor and panel in pixels. |
loop | loop | boolean | true | Wrap focus at the first/last item. |
typeahead | typeahead | boolean | true | First-character typeahead jumps to matching item. |
for | for | string | '' | Anchor element id (forwarded to hy-popover). |
size | size | 'small' | 'medium' | 'medium' | Density variant applied to all descendant menu items that don't have their own size set. hy-menu-button forwards its own size here. |
width | width | string | '' | Fixed panel width (any CSS length, e.g. '220px'). Writes to --hy-menu-width. Leave empty for intrinsic sizing. |
minWidth | min-width | string | '' | Minimum panel width (any CSS length). Writes to --hy-menu-min-width. Leave empty for the default (12rem). |
Events
| Event | Detail | Description |
|---|---|---|
select | — | { value, item, originalEvent } — bubbled up when any child item fires select. |
show | — | { source } — forwarded from the underlying popover (does NOT bubble). |
hide | — | { source } — forwarded from the underlying popover (does NOT bubble). |
request-show | — | { source } — cancelable, forwarded from popover. |
request-hide | — | { source } — cancelable, forwarded from popover. |
Slots
| Slot | Description |
|---|---|
default | Menu items (hy-menu-item, checkbox/radio variants, groups, dividers). |
CSS Parts
| Part | Description |
|---|---|
panel | The popover panel surface (delegated to hy-popover::part(body)). |
CSS Custom Properties
| Property | Description |
|---|---|
--hy-menu-padding-block | — |
--hy-menu-padding-inline | — |
--hy-menu-min-width | Minimum panel width (default: 12rem). Overridden by the min-width attribute. |
--hy-menu-width | Panel width (default: auto). Overridden by the width attribute. |
Methods
show()
Open the menu. When anchor is passed, it becomes the popover's anchor element (an id is generated on the element if it doesn't have one).
focusItem()
Focus a menu item by its index in the collected items list.
getItems()
Return the currently collected items (light-DOM order, including grouped).