1. Kikita UI
  2. Components
  3. Actions
  4. Menu
Skip to content
Kikita UI
  • Installation
  • Theming
  • Tokens
  • Typography
  • Density
  • Accessibility
  • Migrating to 2.0
  • Internationalization
  • Defaults
  • Structural icons
  • Auto Focus
  • Forms
  • AI Support
  • Package Smoke
  • Button
  • Link
  • Icon Button
  • Menu
  • Command Palette
  • Field
  • Input
  • Color Input
  • Select
  • Combobox
  • Date Picker
  • Time Picker
  • Calendar
  • Calendar Range
  • File Upload
  • Segmented
  • Slider
  • Number Input
  • OTP Input
  • Textarea
  • Checkbox
  • Switch
  • Radio
  • Group
  • Badge
  • Loader
  • Skeleton
  • Tooltip
  • Toast
  • Empty State
  • Alert
  • Progress
  • Card
  • Tabs
  • Accordion
  • Breadcrumbs
  • Popover
  • Dialog
  • Media Viewer
  • Drawer
  • Splitter
  • Dropdown
  • Separator
  • Stepper
  • Icon
  • Avatar
  • Table
  • Pagination
  • Line Chart
  • Bar Chart
  • Scatter Chart
  • Donut Chart
  • Carousel
  • Chip
  • Scrollbar
  • Tree
  • Import
  • Usage
  • Content
  • API
  • Accessibility
  • Migrating to 2.0
  • Provider defaults
  • Theming tokens
  • Messages

Actions

Stable - @kikita-labs/ui v2.0.0

Menu

Overlay action menu for commands such as edit, copy, archive, and delete.

Import

Menu composes a panel, trigger directive, menu items, headers, and separators.

menu.ts
import {
  KuiButton,
  KuiMenu,
  KuiMenuFor,
  KuiMenuHeader,
  KuiMenuItem,
  KuiSeparator,
} from '@kikita-labs/ui';

Usage

Open in Playground

Use menu for actions, not value selection. Use Select or Dropdown for picking values.

<div class="basic-menu-example">
  <button kuiButton type="button" [kuiMenuFor]="actionsMenu">Actions</button>

  <kui-menu #actionsMenu ariaLabel="Project actions">
    <button type="button" kuiMenuItem>
      <span class="kui-menu-item__label">Edit</span>
    </button>
    <button type="button" kuiMenuItem>
      <span class="kui-menu-item__label">Copy</span>
    </button>
    <hr kuiSeparator spacing="xs" />
    <button type="button" kuiMenuItem appearance="destructive">
      <span class="kui-menu-item__label">Delete</span>
    </button>
  </kui-menu>
</div>

Content

Headers, icons, shortcuts, disabled states, and destructive actions are projected item content.

<div class="menu-content-example">
  <button kuiButton type="button" shape="outline" [kuiMenuFor]="rowMenu">Row actions</button>

  <kui-menu #rowMenu ariaLabel="Row actions" menuAlign="end" minWidth="220px">
    <div kuiMenuHeader>Project</div>
    <button type="button" kuiMenuItem>
      <span class="kui-menu-item__icon" aria-hidden="true">E</span>
      <span class="kui-menu-item__label">Rename</span>
      <span class="kui-menu-item__shortcut">F2</span>
    </button>
    <button type="button" kuiMenuItem>
      <span class="kui-menu-item__icon" aria-hidden="true">C</span>
      <span class="kui-menu-item__label">Copy link</span>
      <span class="kui-menu-item__shortcut">Ctrl C</span>
    </button>
    <hr kuiSeparator spacing="xs" />
    <button type="button" kuiMenuItem disabled>
      <span class="kui-menu-item__label">Archive</span>
    </button>
  </kui-menu>
</div>

Provider defaults

Set defaults.menu once for the application or for a subtree. Each option resolves as local input > defaults.menu.<option> > built-in default.

import { provideKikitaUi } from '@kikita-labs/ui';

export const appConfig: ApplicationConfig = {
  providers: [
    provideKikitaUi({
      defaults: {
        menu: {
          /* options below */
        },
      },
    }),
  ],
};
NameTypeDefaultDescription
placement'top' | 'bottom' | 'left' | 'right' — Preferred side of the anchor. The overlay flips to the opposite side when it does not fit.
offsetnumber — Gap in px between the anchor and the overlay panel.
menuAlign'start' | 'end' — Alignment along the trigger edge.
minWidthstring | null — Minimum panel width as a CSS length.

Theming tokens

Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.

NameTypeDefaultDescription
--kui-menu-item-shortcut-font-sizeCSS custom property--kui-text-xs-sizeItem shortcut font size

Messages

Every text the component owns (accessible names, visible words, announcements) is a typed message with an English default. Override it for the application with provideKikitaUi({ messages }), or for a subtree with provideKuiMessages.

NameTypeDefaultDescription
labelstring — Accessible name of the menu when ariaLabel is not set. Default Actions.

API

Inputs verified against @kikita-labs/ui v2.0.0 public typings.

NameTypeDefaultDescription
ariaLabelstring | undefinedundefinedAccessible name for the menu panel. Falls back to the menu.label message (Actions).
placement'top' | 'bottom' | 'left' | 'right' | undefinedundefinedPreferred side of the trigger the menu opens on. Falls back to defaults.menu.placement, then bottom. Auto-flips to the opposite side to fit the viewport.
menuAlign'start' | 'end' | undefinedundefinedAlignment along the trigger edge (defaults.menu.menuAlign, then start). For top/bottom placement, start is left-aligned and end is right-aligned. For left/right placement, start is top-aligned and end is bottom-aligned.
offsetnumber | undefinedundefinedPixel gap between the trigger and the menu panel. Falls back to defaults.menu.offset, then 4. A static numeric string is coerced.
minWidthstring | null | undefinedundefinedOptional minimum inline size, applied to the visible panel as well as its overlay pane. Falls back to defaults.menu.minWidth, then none.
[kuiMenuFor]KuiMenu | undefined-Wires a native trigger to a menu instance and manages trigger ARIA state.
kuiMenuHeader--Marks a non-interactive group heading inside the menu panel. Renders with role="presentation".
kuiSeparator--Native hr[kuiSeparator] divider between menu item groups. See the Separator page for spacing and appearance inputs.
kuiMenuItem.appearance'neutral' | 'destructive''neutral'Visual treatment for an action item. Use destructive for dangerous actions.
kuiMenuItem.disabledbooleanfalsePrevents activation and applies disabled/aria-disabled semantics. Disabled items are skipped by keyboard navigation.
isOpenWritableSignal<boolean>falseWhether the menu is currently open. Read it from a template reference.
KuiMenuOptionsinterface-Shape of defaults.menu: placement, offset, menuAlign and minWidth.

Accessibility

Menu owns keyboard navigation while keeping triggers and items native.

  • [kuiMenuFor] sets aria-haspopup="menu" and aria-expanded on the trigger, and adds aria-controls while the panel is open.
  • The panel uses role="menu"; items use role="menuitem".
  • Group headers marked with kuiMenuHeader use role="presentation".
  • Disabled items expose aria-disabled="true" and are skipped by keyboard navigation.
  • ArrowDown and ArrowUp open from the trigger and focus the first or last item.
  • Home, End, and arrow keys move focus inside the menu.
  • Escape closes the menu and returns focus to the trigger.
  • Tab closes the menu and lets focus continue to the next element.
  • With prefers-reduced-motion: reduce the menu closes immediately instead of waiting for its exit animation.
  • Without ariaLabel the panel name comes from the menu.label message, so it follows the active locale.
  • Menu covers keyboard navigation and static ARIA review. Screen reader and other assistive-technology verification has not been completed for this primitive yet; see state-coverage.md in the library repository for current review status.

Migrating to 2.0

Consumer-visible changes of @kikita-labs/ui 2.0 for Menu.

  • The classes are KuiMenu, KuiMenuFor, KuiMenuHeader, KuiMenuItem and KuiSeparator; the Component and Directive suffixes are gone.
  • Placement, offset, alignment and minimum width defaults moved to provideKuiDefaults({ menu: { ... } }); the matching inputs are now undefined until set.
  • The default ariaLabel comes from the menu.label message instead of a fixed English string.
  • minWidth now applies to the visible panel as well as the CDK overlay pane.
  • The menu closes immediately under reduced motion, and its exit animation uses --kui-duration-quick and --kui-ease-exit.
  • Item hover and pressed fills read --kui-color-state-hover and --kui-color-state-active; the shortcut font size is --kui-menu-item-shortcut-font-size.

On this page