HyMenuButton
Usage examples on this page are written for Lit / plain HTML (
<hy-menu-button>). The same component ships asHyMenuButtonin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A trigger + menu pair implementing the ARIA menu-button pattern. The trigger is any element slotted into trigger; the menu surface is the child hy-menu (rendered in the default slot) or an actions shorthand.
Trigger shapes
- Slotted trigger — put any element (hy-button, hy-icon-button, chip, avatar, …) into
slot="trigger". You own the label, icons, and styling. - Default trigger — when
labelis set andslot="trigger"is empty, the component renders an internalhy-button caret truncatewith the label text and a trailing chevron. Thetruncateflag means long labels clip with an ellipsis instead of overflowing the row, so the default trigger is safe to use as a "value picker" reflecting an unbounded current selection. Slotted triggers don't get this for free — settruncateon your ownhy-buttonif you need it.
Composition contract
Slotted hy-menu-item children always win over the actions array — same precedence as hy-menu-item's own label prop losing to the default slot. When both are set in dev mode, a single console warning fires per element.
ARIA wiring
The trigger receives aria-haspopup="menu", aria-expanded, and an aria-controls pointing at the internally managed menu id. Clicks on the trigger toggle the menu; Escape from the menu returns focus to the trigger (delegated to hy-popover). A host aria-label forwards to the default trigger, naming the control when the visible label is a current value (e.g. a picker showing "solid") rather than what the control does.
Examples
Slotted trigger with a divider and a danger action
<hy-menu-button>
<hy-button slot="trigger">
Actions
<hy-icon slot="suffix" name="chevron-down"></hy-icon>
</hy-button>
<hy-menu-item value="edit" label="Edit"></hy-menu-item>
<hy-menu-item value="duplicate" label="Duplicate"></hy-menu-item>
<hy-menu-item value="archive" label="Archive"></hy-menu-item>
<hy-divider role="separator"></hy-divider>
<hy-menu-item value="delete" label="Delete" variant="danger"></hy-menu-item>
</hy-menu-button>Default trigger rendered from the label prop
<hy-menu-button label="Sort by" aria-label="Sort order">
<hy-menu-item value="name" label="Name"></hy-menu-item>
<hy-menu-item value="date" label="Date modified"></hy-menu-item>
<hy-menu-item value="size" label="Size"></hy-menu-item>
</hy-menu-button>
<script>
document.querySelector('hy-menu-button').addEventListener('select', (e) => {
console.log(e.detail.value);
});
</script>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 forwarded to the child menu. |
size | size | 'small' | 'medium' | 'medium' | Density variant forwarded to the child hy-menu (and through it to every menu item). Also sizes the default hy-button trigger (when label renders one). Does not re-size a slotted trigger — consumers size their own trigger element. |
label | label | string | '' | Label used by the default hy-button caret trigger. Ignored when slot="trigger" has content. |
width | width | string | '' | Fixed menu-panel width (any CSS length, e.g. '220px'). Forwarded to the child hy-menu. |
minWidth | min-width | string | '' | Minimum menu-panel width. Forwarded to the child hy-menu. |
fullWidth | full-width | boolean | false | Stretch the trigger to fill the host's inline size. Off by design; opt in for a full-width "select-style" dropdown trigger. The slotted (or default truncate) trigger grows to match. Distinct from width / minWidth, which size the dropped menu panel. |
actions | — | MenuAction[] | [] | Shorthand for rendering items from data. When set, items are rendered only if the default slot is empty. Slotted children always win. |
Events
| Event | Detail | Description |
|---|---|---|
select | — | Relayed from the child menu. Detail: MenuSelectDetail. |
change | — | Relayed from the child menu when a radio group changes. Detail: MenuChangeDetail — { selectedValue, name, reason }. |
show | — | Relayed from the child menu (does NOT bubble). |
hide | — | Relayed from the child menu (does NOT bubble). |
Slots
| Slot | Description |
|---|---|
trigger | The trigger element (button, icon-button, chip, avatar, …). When empty and label is set, an internal hy-button caret truncate is rendered (long labels clip with an ellipsis). |
default | hy-menu-item / hy-menu-item-checkbox / hy-menu-item-radio / hy-menu-group / hy-divider children. |
CSS Parts
| Part | Description |
|---|---|
trigger-wrapper | The wrapper element around the trigger slot. |