Menu

An accessible dropdown / action menu anchored to a trigger. It follows the WAI-ARIA menu button pattern: role="menu" content with role="menuitem" children, arrow-key navigation, typeahead, and submenu support.

Last action: —

Anatomy

Menu.Root shares open state and the trigger reference. Menu.Content renders the role="menu" panel in a portal, positioned against the trigger (default placement bottom-start). Items take an onAction handler and can be disabled.

<script>
	import { Menu } from '@human-kit/ui';
</script>

<Menu.Root>
	<Menu.Trigger>Options</Menu.Trigger>
	<Menu.Content>
		<Menu.Item onAction={edit}>Edit</Menu.Item>
		<Menu.Item disabled>Duplicate</Menu.Item>
		<Menu.Separator />
		<Menu.Group>
			<Menu.GroupLabel>Share</Menu.GroupLabel>
			<Menu.Item onAction={copyLink}>Copy link</Menu.Item>
		</Menu.Group>
	</Menu.Content>
</Menu.Root>

Groups and separators

Group related items with Menu.Group + Menu.GroupLabel — the group renders role="group" labelled by its label — and divide sections with Menu.Separator.

Nest a Menu.SubmenuRoot containing a Menu.SubmenuTrigger and its own Menu.Content (default placement right-start). Submenus use a "safe triangle" pointer intent: while the pointer moves diagonally toward an open submenu, hovering the sibling items it passes over does not close it.

Usage guidelines

  • Use Menu.Root to share open state and the trigger reference, and place Menu.Trigger and Menu.Content inside it.
  • Use Menu.Item for actions. Provide onAction, and optionally disabled, closeOnSelect, or textValue (for typeahead).
  • closeOnSelect (on Menu.Root, overridable per Menu.Item) controls whether activating an item closes the menu. Default true.
  • loop (default true) wraps arrow navigation; typeahead (default true) focuses items by typed text.
  • Group related items with Menu.Group + Menu.GroupLabel, and divide sections with Menu.Separator.
  • onOpenChange(open, details) reports why the state changed (details.reason) and supports details.cancel() to prevent the transition.

Accessibility

  • Menu.Trigger renders a button with aria-haspopup="menu" and aria-expanded; ArrowDown/Enter/Space open the menu and focus the first item, ArrowUp opens and focuses the last item.
  • Menu.Content renders role="menu" and items render role="menuitem"; arrow keys move the highlight, and typeahead focuses items by typed text.
  • Escape closes the current (topmost) menu and returns focus to its trigger; Tab and outside interaction close the whole menu chain.
  • Within a submenu, ArrowLeft closes just that level; ArrowRight on a submenu trigger opens it.

API reference

Root

State container for the menu. Shares open state, the trigger reference, and navigation settings (loop, typeahead, closeOnSelect) with all parts.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Trigger

Button that opens the menu (aria-haspopup="menu", aria-expanded). ArrowDown/Enter/Space open and focus the first item; ArrowUp opens and focuses the last item.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-menu-trigger Identifies the trigger button.

Content

The floating role="menu" panel. Renders in a portal and positions itself against the trigger; also used as the panel of a submenu.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-entering Present while the enter animation is running.
data-exiting Present while the exit animation is running.
data-menu-content Identifies the menu panel element.
data-placement The resolved side of the trigger the panel is on ("top" | "right" | "bottom" | "left").
data-state "open" while the menu is open, "closed" during exit.

Overlay

Optional backdrop rendered behind the menu. Place it as a sibling of Menu.Content inside Menu.Root; in a submenu chain only the root menu should render one.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-entering Present while the enter animation is running.
data-exiting Present while the exit animation is running.
data-menu-overlay Identifies the overlay element.
data-state "open" while the menu is open, "closed" during exit.

Item

An interactive role="menuitem" action. Accepts `onAction`, `disabled`, `closeOnSelect` (overrides the Root default), `textValue` for typeahead, and an optional stable `value`.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-disabled Present when the item is disabled.
data-highlighted Present while the item is highlighted via keyboard navigation or pointer hover.
data-item-id The item's stable identifier (its `value` prop, or an auto-generated id).
data-item-id-type "number" when the item's `value` is numeric; absent for string ids.
data-navigation-item Marks the element as a keyboard-navigable menu item.
data-pressed Present while the item is actively pressed via pointer.
data-text-value The text typeahead matches against, when it differs from the label.

Separator

A visual divider between menu items (role="separator").

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-menu-separator Identifies the separator element.
data-orientation The separator orientation ("horizontal" | "vertical").

Group

Groups related items (role="group"), labelled by an optional Menu.GroupLabel via aria-labelledby.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-menu-group Identifies the group element.

GroupLabel

Accessible label for a Menu.Group. The surrounding group references it through aria-labelledby.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-menu-group-label Identifies the group label element.

SubmenuRoot

State container for a nested submenu. Place it inside a Menu.Content with a Menu.SubmenuTrigger and its own Menu.Content; navigation settings inherit from the parent menu.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

SubmenuTrigger

A role="menuitem" that opens its submenu on hover, ArrowRight, Enter, or Space. Behaves as a navigable item of the parent menu.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-disabled Present when the trigger is disabled.
data-highlighted Present while the trigger is highlighted via keyboard navigation or pointer hover.
data-item-id The trigger's stable identifier (its `value` prop, or an auto-generated id).
data-item-id-type "number" when the trigger's `value` is numeric; absent for string ids.
data-menu-trigger Marks the element as the trigger of its submenu.
data-navigation-item Marks the element as a keyboard-navigable item of the parent menu.
data-submenu-trigger Identifies the submenu trigger element.
data-text-value The text typeahead matches against, when it differs from the label.