Skip to content

HyMenu

Usage examples on this page are written for Lit / plain HTML (<hy-menu>). The same component ships as HyMenu in @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 triggershy-menu-button, hy-context-menu, and hy-menubar-item wrap hy-menu and handle trigger wiring themselves.

Examples

javascript
<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

html
<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

PropertyAttributeTypeDefaultDescription
openopenbooleanfalseControlled open state.
placementplacement'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.
distancedistancenumber4Gap between anchor and panel in pixels.
looploopbooleantrueWrap focus at the first/last item.
typeaheadtypeaheadbooleantrueFirst-character typeahead jumps to matching item.
forforstring''Anchor element id (forwarded to hy-popover).
sizesize'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.
widthwidthstring''Fixed panel width (any CSS length, e.g. '220px'). Writes to --hy-menu-width. Leave empty for intrinsic sizing.
minWidthmin-widthstring''Minimum panel width (any CSS length). Writes to --hy-menu-min-width. Leave empty for the default (12rem).

Events

EventDetailDescription
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

SlotDescription
defaultMenu items (hy-menu-item, checkbox/radio variants, groups, dividers).

CSS Parts

PartDescription
panelThe popover panel surface (delegated to hy-popover::part(body)).

CSS Custom Properties

PropertyDescription
--hy-menu-padding-block
--hy-menu-padding-inline
--hy-menu-min-widthMinimum panel width (default: 12rem). Overridden by the min-width attribute.
--hy-menu-widthPanel 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).

Built with Lit. Documented with VitePress.