Navigationduskmoonimplemented10 demos

Menu

Menu renders structured navigation or action lists.

Import@duskmoon-dev/components/menu
11API sections
40documented props
8behavior scenarios
Key API
itemsselectedKeysdefaultSelectedKeysopenKeysdefaultOpenKeysmode

Usage

When to use

  • Use it when users need to move between sections, pages, steps, or contextual actions.
  • Expose current and disabled state so navigation remains clear to keyboard and screen-reader users.

Implementation notes

StylesheetImport @duskmoon-dev/components/styles.css once in the app or docs shell.
StateStart with default props for static examples, then switch to controlled props when state must be shared.
ThemeThe preview inherits the active DuskMoon data-theme value from the docs layout.

Features

Wayfinding

Covers the route, section, step, or action-list patterns that help users move through an interface.

Current state

Shows selected, active, open, or current props where the component exposes them.

Primary API surface

Menu is most often configured through `items`, `selectedKeys`, `defaultSelectedKeys`, `openKeys`.

Covered behavior

Renders items with DuskMoon menu classes

Feature Demos

Feature demos are authored for the component page, then supplemented with behavior scenarios from the component test coverage.

Preview

Basic usage

authored

Import the component stylesheet and Menu from its package subpath, then render it with the core props.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function Example() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Renders items with DuskMoon menu classes

test-backed

Menu scenario from the component test coverage: renders items with duskmoon menu classes.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuRendersItemsWithDuskMoonDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Supports default selected keys and selection callbacks

test-backed

Menu scenario from the component test coverage: supports default selected keys and selection callbacks.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuSupportsDefaultSelectedKeysDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Supports submenu open state

test-backed

Menu scenario from the component test coverage: supports submenu open state.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuSupportsSubmenuOpenStateDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Supports controlled selected keys

test-backed

Menu scenario from the component test coverage: supports controlled selected keys.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuSupportsControlledSelectedKeysDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Supports multiple deselect

test-backed

Menu scenario from the component test coverage: supports multiple deselect.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuSupportsMultipleDeselectDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Applies mode, theme, size, and disabled classes

test-backed

Menu scenario from the component test coverage: applies mode, theme, size, and disabled classes.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuAppliesModeThemeSizeDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Exposes static child components

test-backed

Menu scenario from the component test coverage: exposes static child components.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuExposesStaticChildComponentsDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview

Forwards root ref

test-backed

Menu scenario from the component test coverage: forwards root ref.

Source
import "@duskmoon-dev/components/styles.css";
import { Menu } from "@duskmoon-dev/components/menu";

export function MenuForwardsRootRefDemo() {
  return (<Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>);
}
Preview
Sunshine Theme
Moonlight Theme

Theme aware

authored

Docs previews inherit the DuskMoon data-theme value. Use the header switch to compare light and dark rendering.

Source
<div data-theme="sunshine">
  <Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>
</div>

<div data-theme="moonlight">
  <Menu
  defaultSelectedKeys={["overview"]}
  defaultOpenKeys={["workspace"]}
  items={[
    { key: "overview", label: "Overview", extra: "⌘1" },
    {
      key: "workspace",
      label: "Workspace",
      children: [
        { key: "tasks", label: "Tasks" },
        { key: "reports", label: "Reports" }
      ]
    },
    { type: "divider" },
    { key: "settings", label: "Settings" }
  ]}
/>
</div>

API

The API reference below lists every parsed exported type or interface for Menu. Start with `items`, `selectedKeys`, `defaultSelectedKeys`, `openKeys` for common usage.

Types: packages/components/src/components/menu/Menu.types.tsScenarios: packages/components/src/components/menu/Menu.test.tsx
MenuPropsinterface extends Omit< ComponentProps<"ul">, "onClick" | "onSelect" >
PropTypeRequiredDescription
itemsMenuItemType[]Noitems configures Menu.
selectedKeysMenuKey[]NoselectedKeys configures Menu.
defaultSelectedKeysMenuKey[]NodefaultSelectedKeys configures Menu.
openKeysMenuKey[]NoopenKeys configures Menu.
defaultOpenKeysMenuKey[]NodefaultOpenKeys configures Menu.
modeMenuModeNomode configures Menu.
themeMenuThemeNotheme configures Menu.
sizeMenuSizeNosize configures Menu.
selectablebooleanNoselectable configures Menu.
multiplebooleanNomultiple configures Menu.
inlineCollapsedbooleanNoinlineCollapsed configures Menu.
disabledbooleanNodisabled configures Menu.
onClick(info: MenuClickInfo) => voidNoonClick configures Menu.
onSelect(info: MenuClickInfo) => voidNoonSelect configures Menu.
onDeselect(info: MenuClickInfo) => voidNoonDeselect configures Menu.
onOpenChange(openKeys: string[]) => voidNoonOpenChange configures Menu.
MenuItemTypeinterface
PropTypeRequiredDescription
keyMenuKeyNokey configures Menu.
labelReactNodeNolabel configures Menu.
titleReactNodeNotitle configures Menu.
iconReactNodeNoicon configures Menu.
extraReactNodeNoextra configures Menu.
childrenMenuItemType[]Nochildren configures Menu.
disabledbooleanNodisabled configures Menu.
dangerbooleanNodanger configures Menu.
type"item" | "group" | "divider"Notype configures Menu.
classNamestringNoclassName configures Menu.
MenuClickInfointerface
PropTypeRequiredDescription
keystringYeskey configures Menu.
keyPathstring[]YeskeyPath configures Menu.
itemMenuItemTypeYesitem configures Menu.
selectedKeysstring[]YesselectedKeys configures Menu.
domEventMouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>YesdomEvent configures Menu.
MenuItemPropsinterface extends ComponentProps<"li">
PropTypeRequiredDescription
disabledbooleanNodisabled configures Menu.
dangerbooleanNodanger configures Menu.
activebooleanNoactive configures Menu.
iconReactNodeNoicon configures Menu.
extraReactNodeNoextra configures Menu.
MenuItemGroupPropsinterface extends Omit< ComponentProps<"li">, "title" >
PropTypeRequiredDescription
titleReactNodeNotitle configures Menu.
MenuComponentinterface extends ForwardRefExoticComponent< MenuProps & RefAttributes<HTMLUListElement> >
PropTypeRequiredDescription
ItemForwardRefExoticComponent<MenuItemProps & RefAttributes<HTMLLIElement>>YesItem configures Menu.
DividerForwardRefExoticComponent<YesDivider configures Menu.
ItemGroupForwardRefExoticComponent<YesItemGroup configures Menu.
MenuKeytype
string | number
MenuModetype
"vertical" | "horizontal" | "inline"
MenuThemetype
"light" | "dark"
MenuSizetype
"sm" | "md" | "lg"
MenuDividerPropstype
ComponentProps<"li">