# Menubar

A desktop-style row of menus (File, Edit, View) in Candor's theme (Radix). Arrow keys move between the menus and along each menu's items, Right and Left open and close submenus, Escape closes the open menu and returns focus to its trigger. An item that can't be used stays in the menu, marked and explained, instead of vanishing.

- Registry name: `menubar` (`@candor/menubar`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/menubar

## Install

```bash
npx candor-ui add menubar
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/menubar`.
It brings in: motion, render-prop, tokens, utils.
npm packages: lucide-react@^1.67.0, radix-ui@^1.8.1.

## Example

```tsx
"use client"

import * as React from "react"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/candor/ui/menubar"

export default function Example() {
  const [grid, setGrid] = React.useState(true)
  const [density, setDensity] = React.useState("comfortable")
  return (
    <Menubar>
      <MenubarMenu>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>
            New report <MenubarShortcut>⌘N</MenubarShortcut>
          </MenubarItem>
          <MenubarSub>
            <MenubarSubTrigger>Export</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>CSV</MenubarItem>
              <MenubarItem>PDF</MenubarItem>
              <MenubarItem locked="Needs the data add-on.">Parquet</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem variant="destructive">Delete report</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent>
          <MenubarCheckboxItem checked={grid} onCheckedChange={setGrid}>
            Show gridlines
          </MenubarCheckboxItem>
          <MenubarSeparator />
          <MenubarRadioGroup value={density} onValueChange={setDensity}>
            <MenubarRadioItem value="compact">Compact</MenubarRadioItem>
            <MenubarRadioItem value="comfortable">Comfortable</MenubarRadioItem>
          </MenubarRadioGroup>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## <Menubar>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Root>`.

## <MenubarCheckboxItem>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>`.

## <MenubarContent>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Content>`.

## <MenubarGroup>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Group>`.

## <MenubarItem>

Props:

- `inset?: boolean | undefined`: Indents the item to line up with items that have an icon.
- `variant?: "default" | "destructive" | undefined` (default `"default"`): destructive colours the item for actions that remove or can't be undone.
- `locked?: string | undefined`: Why the item can't be used right now. When set, it stays in the menu and in the arrow-key order, marked `aria-disabled`, choosing it does nothing and keeps the menu open, and the reason is printed beside it and read to screen readers.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Item>`.

## <MenubarLabel>

Props:

- `inset?: boolean | undefined`: Indents the label to line up with items that have an icon.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Label>`.

## <MenubarMenu>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Menu>`.

## <MenubarPortal>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Portal>`.

## <MenubarRadioGroup>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.RadioGroup>`.

## <MenubarRadioItem>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.RadioItem>`.

## <MenubarSeparator>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Separator>`.

## <MenubarShortcut>

No props.

Also takes the props of `React.ComponentProps<"span">`.

## <MenubarSub>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Sub>`.

## <MenubarSubContent>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.SubContent>`.

## <MenubarSubTrigger>

Props:

- `inset?: boolean | undefined`: Indents the trigger to line up with items that have an icon.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.SubTrigger>`.

## <MenubarTrigger>

No props.

Also takes the props of `React.ComponentProps<typeof MenubarPrimitive.Trigger>`, `RenderProp`.

## Motion

- **open** (overlay, scale): A menu fades in over the overlay family's duration (200 ms in, 120 ms out by default) and scales up from 0.95 from where it is anchored (the menu's trigger, or for a submenu the item that opened it).
- **sub-open** (overlay, scale): A submenu fades in and scales up a little from the item that opened it when the person opens it with the pointer or an arrow key, and fades out when it closes. Under reduced motion it is a short fade.

Set with `--cd-motion-menubar-<moment>-*` in your brand file; the families are in the design reference.

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
