Skip to content

HyMenuItem ​

Usage examples on this page are written for Lit / plain HTML (<hy-menu-item>). The same component ships as HyMenuItem in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

Used inside <hy-menu> — it only means something as part of it.

A row inside an hy-menu. Renders a role="menuitem" button (or an <a> when href is set) with optional leading icon, trailing indicator, and shortcut hint.

The item emits select on activation. When href is set, the event fires synchronously before navigation; calling event.preventDefault() on the select event cancels the link follow. This matches native <a> + click semantics and lets consumers gate navigation (e.g. unsaved changes prompts).

Focus is driven by the parent hy-menu via roving tabindex on the shadow button — the item does not manage its own focusedness. That button is the one element carrying the item role and its state (aria-disabled, aria-haspopup, aria-expanded); the host is role="none", so the accessibility tree holds a single item, and the element that has focus is the element that is announced.

When not to use

  • An option that is on or off: hy-menu-item-checkbox.
  • One option out of a set: hy-menu-item-radio.

Examples ​

Items with shortcut hints and a danger action ​

html
<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" disabled></hy-menu-item>
<hy-menu-item value="delete" label="Delete" variant="danger"></hy-menu-item>

An hy-menu placed as a direct child makes the row a submenu owner: it draws a trailing chevron-right (mirrored in right-to-left text), carries aria-haspopup="menu" and an aria-expanded that follows the submenu, and a click, Enter or Space opens the submenu instead of firing select (ArrowRight and pointer hover, handled by the parent menu, open it too; hovering another row closes it). The submenu opens beside the row — right-start, left-start in right-to-left text — unless it sets its own placement. The nested menu is moved to the item's submenu slot, outside the row's button, so a click inside the submenu never activates the row. A slotted trailing element replaces the chevron.

Row owning a submenu ​

html
<hy-menu-item value="share" label="Share">
  <hy-menu>
    <hy-menu-item value="email" label="Email"></hy-menu-item>
    <hy-menu-item value="link" label="Copy link"></hy-menu-item>
  </hy-menu>
</hy-menu-item>

Item with a description line ​

html
<hy-menu-item value="attach" label="Attach file" description=".pdf, .png, .jpeg or .md, .txt">
  <hy-icon slot="leading" name="paperclip" decorative></hy-icon>
</hy-menu-item>
html
<hy-menu-item value="docs" href="/docs" label="Documentation">
  <hy-icon slot="leading" name="information" decorative></hy-icon>
</hy-menu-item>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
valuevaluestring''Identifier used in the select event detail.
labellabelstring''Label text. When empty, the default slot is rendered instead.
descriptiondescriptionstring''A second line under the label, in the subtle ink and caption type — what the item accepts, what it will do. Wraps (the label keeps its ellipsis) and is announced as the item's description, not as part of its name.
shortcutshortcutstring''Keyboard shortcut hint (plain string; platform formatting is the consumer's job).
disableddisabledbooleanfalseDisables the item — skipped in keyboard navigation, no select emission.
variantvariant'default' | 'danger''default'Visual variant. danger signals a destructive action.
sizesize'small' | 'medium''medium'Density variant. small matches hy-list size="small" density for overflow menus / compact triggers. Usually set by a parent hy-menu or hy-menu-button rather than per-item.
hrefhrefstring''When set, renders as an anchor. select still fires before navigation.
targettargetstring''Anchor target — only meaningful when href is set.
activeactivebooleanfalseWhether this item currently owns the tab stop in its menu's roving tabindex. Reflected so the modal focus trap can match hy-menu-item[active] and so consumer CSS can highlight the current item. Managed by the parent hy-menu — do not set manually.

Events ​

EventDetailDescription
select—{ value, item, originalEvent } — bubbles to parent menu. Not fired by a submenu owner, whose activation opens its submenu.

Slots ​

SlotDescription
defaultA direct hy-menu child is the row's submenu (the row moves it to an internal slot outside its button; don't set a slot on it). The row's text is label.
leadingLeading icon or avatar.
trailingTrailing indicator (check, badge). The shortcut text takes this spot when no trailing slot is provided; a submenu owner draws its own chevron here.

CSS Parts ​

PartDescription
baseThe interactive button/anchor element.
prefixThe leading slot container.
labelThe label text container.
descriptionThe description line under the label.
suffixThe trailing slot container.
shortcutThe shortcut hint text.
submenu-iconThe chevron a submenu owner draws.

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-menu-item-background-resttransparent—
--hy-menu-item-background-neutral-hovervar(--hy-background-neutral-hover)—
--hy-menu-item-background-danger-tint-subtlevar(--hy-background-danger-tint-subtle)—
--hy-menu-item-foreground-default-restvar(--hy-foreground-default-rest)—
--hy-menu-item-foreground-subtle-restvar(--hy-foreground-subtle-rest)—
--hy-menu-item-foreground-danger-restvar(--hy-foreground-danger-rest)—
--hy-menu-item-foreground-default-disabledvar(--hy-foreground-default-disabled)—
--hy-menu-item-gap-row-list-md-inlinevar(--hy-gap-row-list-md-inline)—
--hy-menu-item-gap-row-list-sm-inlinevar(--hy-gap-row-list-sm-inline)—
--hy-menu-item-padding-row-list-md-blockvar(--hy-padding-row-list-md-block)—
--hy-menu-item-padding-row-list-sm-blockvar(--hy-padding-row-list-sm-block)—
--hy-menu-item-padding-row-list-md-inlinevar(--hy-padding-row-list-md-inline)—
--hy-menu-item-padding-row-list-sm-inlinevar(--hy-padding-row-list-sm-inline)—
--hy-menu-item-radius-row-list-smvar(--hy-radius-row-list-sm)—

Methods ​

focus() ​

Imperative focus — called by the parent menu's roving tabindex logic.

setTabIndex() ​

Sets the internal button/anchor's tabindex AND mirrors the tab-stop state to the host's reflected [active] attribute so the focus trap can see which item is the current tab stop. Called by the parent menu's roving-tabindex controller.

Built with Lit. Documented with VitePress.