Menu
v1.0.0Menus expose compact sets of application actions.
Action menu
Use action menus for related commands. The static preview includes icons, descriptions, shortcuts, disabled and destructive states.
Selection states
Use menuitemcheckbox or menuitemradio only for checked choices, always with aria-checked. Group radios with data-menu-group; selection closes the menu and restores trigger focus.
End alignment and viewport edges
An end-aligned menu stays anchored to the trigger’s logical end edge.
Navigation disclosure
A navigation dropdown is not an action menu. Use native details/summary, links in a labelled nav and no menu roles. .menu-align-end provides CSS-only alignment.
This static preview shows the navigation surface.
Interactive
Combine [data-menu], a button trigger and role=“menu”. The Showcase runtime manages aria-expanded, focus and keys.
<div class="menu" data-menu>
<button
class="btn menu-trigger"
type="button"
id="actions-trigger"
aria-haspopup="menu"
aria-expanded="false"
aria-controls="actions-menu"
popovertarget="actions-menu"
data-menu-trigger>
Actions
</button>
<div
class="menu-popup"
id="actions-menu"
role="menu"
aria-labelledby="actions-trigger"
popover="manual"
hidden
data-menu-popup>
<a class="menu-item" role="menuitem" href="/records/42">View details</a>
<button class="menu-item" type="button" role="menuitem">Duplicate</button>
<button class="menu-item" type="button" role="menuitem" disabled>Move</button>
<hr class="menu-separator" role="separator" />
<button class="menu-item menu-item-destructive" type="button" role="menuitem">
Delete
</button>
</div>
</div>
Keyboard and lifecycle contract
- Enter, Space or Arrow Down opens at the first enabled item; Arrow Up opens at the last.
- Arrow keys wrap; Home/End jump to an edge; typing searches items.
- Escape closes and restores trigger focus. Activation closes; button and selection actions restore focus. Tab, focus departure or outside pointer input closes without moving focus.
- Only one menu stays open; initialization is idempotent after Astro page swaps.
The package ships styles only; applications implement this behavior. The Showcase uses native Popover when available and a hidden fallback that cannot escape clipping. Nested submenus are unsupported; use a flat menu or dialog.
CSS Variables
Override these variables on .menu or an ancestor. Positioning expects resolvable lengths for --menu-offset and --menu-viewport-inset.
--menu-min-width: 12rem;
--menu-max-width: 22rem;
--menu-max-height: 20rem;
--menu-available-height: calc(100vh - 1rem);
--menu-offset: var(--spacer-2);
--menu-viewport-inset: var(--spacer-2);
--menu-padding-y: var(--spacer-1);
--menu-padding-x: var(--spacer-1);
--menu-gap: var(--spacer-1);
--menu-bg-color: var(--bg-surface);
--menu-color: var(--text-color);
--menu-border-width: var(--border-width);
--menu-border-color: var(--border-color);
--menu-border-radius: var(--border-radius);
--menu-box-shadow: var(--shadow-lg);
--menu-z-index: var(--z-index-tooltip);
--menu-item-padding-y: var(--spacer-2);
--menu-item-padding-x: var(--spacer-3);
--menu-item-gap: var(--spacer-2);
--menu-item-border-radius: var(--border-radius-sm);
--menu-item-hover-bg-color: var(--bg-surface-hover);
--menu-item-active-bg-color: var(--bg-active);
--menu-item-current-color: var(--action-color);
--menu-item-destructive-color: var(--error);
--menu-item-disabled-color: var(--disabled-text-color);
--menu-item-description-color: var(--text-muted);
--menu-item-shortcut-color: var(--text-muted);
--menu-group-label-color: var(--text-muted);
--menu-separator-color: var(--border-color);
--menu-transition-duration: var(--transition-duration-fast);
--menu-transition-easing: var(--transition-easing);