GitHub

/ menu

Menu

@kumiki/components/menu

Compound <Root> / <Trigger> / <Menu> / <Item> / <Separator> for action menus. Single-level; submenus deferred.

This component, layer by layer

Styled, copy-paste presets (preview). Run pnpm kumiki add to drop the source into your project, then edit freely.

Live preview

Live preview…

Install
pnpm add @kumiki/atelier
Menu (single-level)
<script lang="ts">
  import { Tailwind as Menu } from '@kumiki/atelier/menu';
  import type { MenuItem } from '@kumiki/components/menu';

  const items: MenuItem[] = [
    { id: 'save',      label: 'Save' },
    { id: 'duplicate', label: 'Duplicate' },
    { id: 'sep',       label: '', kind: 'separator' },
    { id: 'delete',    label: 'Delete' },
  ];
</script>

<Menu.Root {items} onSelect={(item) => console.log(item.id)}>
  {#snippet children({ items: live })}
    <Menu.Trigger>Actions ▾</Menu.Trigger>
    <Menu.Menu>
      {#each live as item (item.id)}
        {#if item.kind === 'separator'}
          <Menu.Separator {item} />
        {:else}
          <Menu.Item {item}>{item.label}</Menu.Item>
        {/if}
      {/each}
    </Menu.Menu>
  {/snippet}
</Menu.Root>

/ accessibility

Accessibility

axe-core — run on every PR (LTR + RTL × every documented state).

Keyboard

KeyEffect
Arrow ↓ / ↑Move active item.
Home / EndFirst / last item.
Type-aheadJump to item by initial char.
EnterActivate item.

Test discipline

  • axe-core — run on every PR (LTR + RTL × every documented state).
  • APG keyboard tests — Playwright, hand-written per pattern.
  • VoiceOver / NVDA — Guidepup nightly schedule.
  • Type-level required names — title / aria-label / aria-labelledby.
Read the W3C ARIA APG pattern ↗