

<Preview name="WithGroupsMenuExample" />

## Overview [#overview]

The `Menu` component displays a list of actions or options in a popup, triggered by a button. Built on Base UI Menu primitives, it supports checkboxes, radio groups, submenus, keyboard navigation, and fully customizable styling.

## Usage [#usage]

```tsx
import {
  Menu,
  MenuContent,
  MenuItem,
  MenuTrigger,
} from "@tilt-legal/cubitt-components/primitives";
```

```tsx
<Menu>
  <MenuTrigger render={<Button />}>Open Menu</MenuTrigger>
  <MenuContent>
    <MenuItem>Profile</MenuItem>
    <MenuItem>Settings</MenuItem>
  </MenuContent>
</Menu>
```

<Accordions type="single">
  <Accordion title="Polymorphic Rendering">
    The `MenuTrigger` uses Base UI's `render` prop pattern. This allows you to compose the trigger with any component:

    ```tsx
    <MenuTrigger render={<Button variant="secondary" />}>Open Menu</MenuTrigger>
    ```

    When using `render={<Component />}`, the children of `MenuTrigger` become the children of the rendered component.
  </Accordion>
</Accordions>

## Examples [#examples]

### With Labels [#with-labels]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="WithLabelsMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      Menu,
      MenuContent,
      MenuItem,
      MenuGroupLabel,
      MenuSeparator,
      MenuShortcut,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";

    <Menu>
      <MenuTrigger render={<Button variant="secondary" />}>Open Menu</MenuTrigger>
      <MenuContent className="w-56">
        <MenuGroup>
          <MenuGroupLabel>My Account</MenuGroupLabel>
        </MenuGroup>
        <MenuSeparator />
        <MenuItem>
          <User />
          Profile
          <MenuShortcut>⇧⌘P</MenuShortcut>
        </MenuItem>
        <MenuItem>
          <CreditCard />
          Billing
          <MenuShortcut>⌘B</MenuShortcut>
        </MenuItem>
      </MenuContent>
    </Menu>
    ```
  </Tab>
</Tabs>

### With Checkboxes [#with-checkboxes]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="WithCheckboxesMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      Menu,
      MenuCheckboxItem,
      MenuContent,
      MenuGroup,
      MenuGroupLabel,
      MenuSeparator,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";
    import {
      MenuContent,
      MenuGroup,
      MenuGroupLabel,
      MenuRadioGroup,
      MenuRadioItem,
      MenuSeparator,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";
    import {
      useState } from "react";

    function Example() {
    const [showStatusBar,
      setShowStatusBar] = useState(true);
    const [showActivityBar,
      setShowActivityBar] = useState(false);

      return (
        <Menu>
          <MenuTrigger render={<Button variant="secondary" />}>View Options</MenuTrigger>
          <MenuContent className="w-56">
            <MenuGroup>
              <MenuGroupLabel>Appearance</MenuGroupLabel>
            </MenuGroup>
            <MenuSeparator />
            <MenuCheckboxItem
              checked={showStatusBar}
              onCheckedChange={setShowStatusBar}
            >
              Status Bar
            </MenuCheckboxItem>
            <MenuCheckboxItem
              checked={showActivityBar}
              onCheckedChange={setShowActivityBar}
            >
              Activity Bar
            </MenuCheckboxItem>
          </MenuContent>
        </Menu>
      );

    }

    ```
  </Tab>
</Tabs>

### With Radio Group [#with-radio-group]

<Tabs
  items="['Preview',
  'Code']"
>
  <Tab value="Preview">
    <Preview name="WithRadioGroupMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Menu } from "@tilt-legal/cubitt-components/primitives";
    import {
      MenuContent,
      MenuItem,
      MenuSeparator,
      MenuSubmenuRoot,
      MenuContent,
      MenuSubmenuTrigger,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";
    import {
      useState } from "react";

    function Example() {
      const [position,
      setPosition] = useState("bottom");

      return (
        <Menu>
          <MenuTrigger render={<Button variant="secondary" />}>Panel Position</MenuTrigger>
          <MenuContent className="w-56">
            <MenuGroup>
              <MenuGroupLabel>Panel Position</MenuGroupLabel>
            </MenuGroup>
            <MenuSeparator />
            <MenuRadioGroup value={position} onValueChange={setPosition}>
              <MenuRadioItem value="top">Top</MenuRadioItem>
              <MenuRadioItem value="bottom">Bottom</MenuRadioItem>
              <MenuRadioItem value="right">Right</MenuRadioItem>
            </MenuRadioGroup>
          </MenuContent>
        </Menu>
      );
    }
    ```
  </Tab>
</Tabs>

### With Submenu [#with-submenu]

<Tabs
  items="['Preview',
'Code']"
>
  <Tab value="Preview">
    <Preview name="WithSubmenuMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Menu } from "@tilt-legal/cubitt-components/primitives";

    <Menu>
      <MenuTrigger render={<Button variant="secondary" />}>Open Menu</MenuTrigger>
      <MenuContent className="w-56">
        <MenuItem>Profile</MenuItem>
        <MenuItem>Billing</MenuItem>
        <MenuSeparator />
        <MenuSubmenuRoot>
          <MenuSubmenuTrigger>
            <UserPlus />
            Invite users
          </MenuSubmenuTrigger>
          <MenuContent>
            <MenuItem>
              <Mail />
              Email
            </MenuItem>
            <MenuItem>
              <MessageSquare />
              Message
            </MenuItem>
          </MenuContent>
        </MenuSubmenuRoot>
      </MenuContent>
    </Menu>
    ```
  </Tab>
</Tabs>

### With Groups [#with-groups]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="WithGroupsMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      Menu,
      MenuContent,
      MenuGroup,
      MenuItem,
      MenuGroupLabel,
      MenuSeparator,
      MenuShortcut,
      MenuSubmenuRoot,
      MenuContent,
      MenuSubmenuTrigger,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";

    <Menu>
      <MenuTrigger render={<Button variant="secondary" />}>Open Menu</MenuTrigger>
      <MenuContent className="w-56">
        <MenuGroup>
          <MenuGroupLabel>My Account</MenuGroupLabel>
        </MenuGroup>
        <MenuSeparator />
        <MenuGroup>
          <MenuItem>
            Profile
            <MenuShortcut>⇧⌘P</MenuShortcut>
          </MenuItem>
          <MenuItem>
            Billing
            <MenuShortcut>⌘B</MenuShortcut>
          </MenuItem>
        </MenuGroup>
        <MenuSeparator />
        <MenuGroup>
          <MenuItem>Team</MenuItem>
          <MenuSubmenuRoot>
            <MenuSubmenuTrigger>Invite users</MenuSubmenuTrigger>
            <MenuContent>
              <MenuItem>Email</MenuItem>
              <MenuItem>Message</MenuItem>
            </MenuContent>
          </MenuSubmenuRoot>
        </MenuGroup>
      </MenuContent>
    </Menu>
    ```
  </Tab>
</Tabs>

### With Destructive Action [#with-destructive-action]

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="WithDestructiveMenuExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      Menu,
      MenuContent,
      MenuItem,
      MenuSeparator,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";

    <Menu>
      <MenuTrigger render={<Button variant="secondary" />}>Actions</MenuTrigger>
      <MenuContent className="w-56">
        <MenuItem>Edit</MenuItem>
        <MenuItem>Duplicate</MenuItem>
        <MenuItem>Archive</MenuItem>
        <MenuSeparator />
        <MenuItem variant="destructive">Delete</MenuItem>
      </MenuContent>
    </Menu>
    ```
  </Tab>
</Tabs>

### URL State [#url-state]

Trigger URL state changes by providing `paramName`/`paramSetValue` to individual `MenuItem` elements. Useful for opening dialogs, sheets, or other components when a menu item is selected.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="MenuUrlStateExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import {
      Menu,
      MenuContent,
      MenuItem,
      MenuTrigger,
      Button,
    } from "@tilt-legal/cubitt-components/primitives";
    export default function Component() {
      return (
        <Menu>
          <MenuTrigger render={<Button variant="secondary" />}>Actions</MenuTrigger>
          <MenuContent className="w-48">
            <MenuItem paramName="menu-action" paramSetValue="profile">
              Profile
            </MenuItem>
            <MenuItem paramName="menu-action" paramSetValue="billing">
              Billing
            </MenuItem>
            <MenuItem paramName="menu-action" paramSetValue="logout">
              Log out
            </MenuItem>
          </MenuContent>
        </Menu>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Menu [#menu]

The root component that manages the menu state.

| Prop           | Type                                    | Description                                                             |
| -------------- | --------------------------------------- | ----------------------------------------------------------------------- |
| `open`         | `boolean`                               | Whether the menu is currently open (controlled).                        |
| `defaultOpen`  | `boolean`                               | Whether the menu is initially open (uncontrolled). Defaults to `false`. |
| `onOpenChange` | `(open: boolean, eventDetails) => void` | Callback fired when the open state changes.                             |
| `modal`        | `boolean`                               | Whether the menu is modal (locks document scroll). Defaults to `true`.  |
| `disabled`     | `boolean`                               | Whether the menu is disabled. Defaults to `false`.                      |
| `openOnHover`  | `boolean`                               | Whether to open the menu on hover. Defaults to `false`.                 |
| `delay`        | `number`                                | Delay in milliseconds before opening on hover. Defaults to `100`.       |
| `closeDelay`   | `number`                                | Delay in milliseconds before closing on hover. Defaults to `0`.         |
| `loop`         | `boolean`                               | Whether to loop keyboard focus. Defaults to `true`.                     |
| `orientation`  | `"horizontal" \| "vertical"`            | The visual orientation of the menu. Defaults to `"vertical"`.           |

### MenuTrigger [#menutrigger]

The button that toggles the dropdown menu.

| Prop        | Type                                      | Description                                                                    |
| ----------- | ----------------------------------------- | ------------------------------------------------------------------------------ |
| `className` | `string`                                  | Additional CSS classes for the trigger.                                        |
| `render`    | `ReactElement \| (props) => ReactElement` | Allows composing the trigger with another component. Receives props to spread. |
| `disabled`  | `boolean`                                 | Whether the trigger is disabled. Defaults to `false`.                          |

### MenuContent [#menucontent]

The container for the menu items, positioned relative to the trigger.

| Prop          | Type                                     | Description                                                    |
| ------------- | ---------------------------------------- | -------------------------------------------------------------- |
| `className`   | `string`                                 | Additional CSS classes for the content.                        |
| `align`       | `"start" \| "center" \| "end"`           | Alignment relative to the trigger. Defaults to `"center"`.     |
| `side`        | `"top" \| "right" \| "bottom" \| "left"` | Which side of the trigger to position. Defaults to `"bottom"`. |
| `sideOffset`  | `number`                                 | Distance in pixels from the trigger. Defaults to `4`.          |
| `alignOffset` | `number`                                 | Offset in pixels along the alignment axis. Defaults to `0`.    |

### MenuItem [#menuitem]

An individual selectable item in the menu.

| Prop           | Type                | Description                                                          |
| -------------- | ------------------- | -------------------------------------------------------------------- |
| `className`    | `string`            | Additional CSS classes for the item.                                 |
| `disabled`     | `boolean`           | Whether the item is disabled. Defaults to `false`.                   |
| `variant`      | `"destructive"`     | Visual variant for the item. Use `"destructive"` for delete actions. |
| `inset`        | `boolean`           | Whether to add left padding for alignment with labeled items.        |
| `closeOnClick` | `boolean`           | Whether to close the menu when clicked. Defaults to `true`.          |
| `onClick`      | `MouseEventHandler` | Click handler for the item.                                          |

#### URL State Props [#url-state-props]

When provided with a `paramName`, the menu item will set URL parameters when clicked.

| Prop             | Type     | Description                                                   |
| ---------------- | -------- | ------------------------------------------------------------- |
| `paramName?`     | `string` | Optional URL parameter name to set when the item is selected. |
| `paramSetValue?` | `string` | Value written to the URL when the item is selected.           |
| `paramThrottle?` | `number` | Throttle URL updates in milliseconds.                         |
| `paramDebounce?` | `number` | Debounce URL updates in milliseconds.                         |

### MenuCheckboxItem [#menucheckboxitem]

A menu item with a checkbox.

| Prop              | Type                         | Description                                    |
| ----------------- | ---------------------------- | ---------------------------------------------- |
| `className`       | `string`                     | Additional CSS classes for the checkbox item.  |
| `checked`         | `boolean`                    | Whether the checkbox is checked.               |
| `onCheckedChange` | `(checked: boolean) => void` | Callback fired when the checked state changes. |
| `disabled`        | `boolean`                    | Whether the checkbox item is disabled.         |

### MenuRadioGroup [#menuradiogroup]

A group of radio items where only one can be selected.

| Prop            | Type                      | Description                                     |
| --------------- | ------------------------- | ----------------------------------------------- |
| `value`         | `string`                  | The value of the selected radio item.           |
| `onValueChange` | `(value: string) => void` | Callback fired when the selected value changes. |

### MenuRadioItem [#menuradioitem]

An individual radio item within a radio group.

| Prop        | Type      | Description                                |
| ----------- | --------- | ------------------------------------------ |
| `className` | `string`  | Additional CSS classes for the radio item. |
| `value`     | `string`  | The value of this radio item. Required.    |
| `disabled`  | `boolean` | Whether the radio item is disabled.        |

### MenuGroupLabel [#menugrouplabel]

A label for a section of menu items.

**Important:** `MenuGroupLabel` must be used within a `MenuGroup` component due to Base UI's context requirements.

| Prop        | Type      | Description                                |
| ----------- | --------- | ------------------------------------------ |
| `className` | `string`  | Additional CSS classes for the label.      |
| `inset`     | `boolean` | Whether to add left padding for alignment. |

### MenuSeparator [#menuseparator]

A visual separator between menu items.

| Prop        | Type     | Description                               |
| ----------- | -------- | ----------------------------------------- |
| `className` | `string` | Additional CSS classes for the separator. |

### MenuGroup [#menugroup]

Groups related menu items together.

| Prop        | Type     | Description                           |
| ----------- | -------- | ------------------------------------- |
| `className` | `string` | Additional CSS classes for the group. |

### MenuSubmenuRoot [#menusubmenuroot]

The root component for a submenu.

| Prop           | Type                      | Description                                           |
| -------------- | ------------------------- | ----------------------------------------------------- |
| `open`         | `boolean`                 | Whether the submenu is open (controlled).             |
| `defaultOpen`  | `boolean`                 | Whether the submenu is initially open (uncontrolled). |
| `onOpenChange` | `(open: boolean) => void` | Callback fired when the open state changes.           |
| `disabled`     | `boolean`                 | Whether the submenu is disabled.                      |

### MenuSubmenuTrigger [#menusubmenutrigger]

The trigger button for a submenu.

| Prop        | Type      | Description                                     |
| ----------- | --------- | ----------------------------------------------- |
| `className` | `string`  | Additional CSS classes for the submenu trigger. |
| `inset`     | `boolean` | Whether to add left padding for alignment.      |
| `disabled`  | `boolean` | Whether the submenu trigger is disabled.        |

### MenuContent [#menucontent-1]

The content container for a submenu.

| Prop          | Type                                     | Description                                                 |
| ------------- | ---------------------------------------- | ----------------------------------------------------------- |
| `className`   | `string`                                 | Additional CSS classes for the submenu content.             |
| `align`       | `"start" \| "center" \| "end"`           | Alignment relative to the trigger.                          |
| `side`        | `"top" \| "right" \| "bottom" \| "left"` | Which side to position the submenu.                         |
| `sideOffset`  | `number`                                 | Distance in pixels from the trigger. Defaults to `4`.       |
| `alignOffset` | `number`                                 | Offset in pixels along the alignment axis. Defaults to `0`. |

### MenuShortcut [#menushortcut]

A utility component for displaying keyboard shortcuts.

| Prop        | Type     | Description                                      |
| ----------- | -------- | ------------------------------------------------ |
| `className` | `string` | Additional CSS classes for the shortcut display. |
