Skip to content

Actions & Overlays

Menu

A menubar with single-level submenus.

stableEnhancer: enhanceMenuBuilt on <ul role="menubar">hydrateless/menu.css

A menubar or navigation menu with single-level submenus, following the WAI-ARIA menubar pattern. The enhancer wires a roving tabindex, orientation-aware arrow navigation, submenu toggling, and typeahead. Submenus are promoted to native popovers so they render in the top layer, positioned against their trigger with CSS anchor positioning (with a JS fallback).

Menubar

Arrow keys move between items; Enter or an arrow opens a submenu.

Live

JavaScript

This component ships an optional enhancer. With auto-init it loads automatically; to wire it yourself, import it directly:

import { enhanceMenu } from '@hydrateless/enhancers/menu';

const handle = enhanceMenu(container, { orientation, onOpenChange, onSelect });
// handle.api  -> imperative controls
// handle.destroy()  -> tear everything down

Props

The framework bindings expose these props (and forward the rest to the root element).

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''horizontal'Direction of the top-level items.
openstring | nullControlled open submenu value; pair with `onOpenChange`.
onSelect(value: string) => voidCalled with the item value when a leaf menu item is activated.

Events and callbacks

Event / CallbackPayloadDescription
hl:open-change{ open: boolean, value: string | null }Fires when a submenu opens or closes, with the open submenu value.
hl:select{ value: string, item: HTMLElement }Fires when a leaf item is activated. Cancelable.

CSS variables

Override these on any ancestor to theme the component. See the theme studio to preview changes live.

CSS variableUsed for
--hl-surfaceSubmenu background.
--hl-borderSubmenu border.
--hl-shadow-mdSubmenu elevation.

Accessibility

  • A roving tabindex keeps the menubar a single tab stop.
  • Submenu triggers expose aria-haspopup, aria-expanded, and aria-controls.

Released under the MIT License.