# Menubar

Provides a persistent set of application commands.

```tsx
import * as stylex from "@stylexjs/stylex"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/ui/menubar"

const styles = stylex.create({ menubar: { width: "18rem" }, content: { width: "11rem" } })

export default function MenubarDemo() {
  return (
    <Menubar xstyle={styles.menubar}>
      <MenubarMenu>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              New Tab <MenubarShortcut>⌘T</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              New Window <MenubarShortcut>⌘N</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled>New Incognito Window</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarSub>
              <MenubarSubTrigger>Share</MenubarSubTrigger>
              <MenubarSubContent>
                <MenubarGroup>
                  <MenubarItem>Email link</MenubarItem>
                  <MenubarItem>Messages</MenubarItem>
                  <MenubarItem>Notes</MenubarItem>
                </MenubarGroup>
              </MenubarSubContent>
            </MenubarSub>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem>
              Print... <MenubarShortcut>⌘P</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Edit</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              Undo <MenubarShortcut>⌘Z</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarSub>
              <MenubarSubTrigger>Find</MenubarSubTrigger>
              <MenubarSubContent>
                <MenubarGroup>
                  <MenubarItem>Search the web</MenubarItem>
                </MenubarGroup>
                <MenubarSeparator />
                <MenubarGroup>
                  <MenubarItem>Find...</MenubarItem>
                  <MenubarItem>Find Next</MenubarItem>
                  <MenubarItem>Find Previous</MenubarItem>
                </MenubarGroup>
              </MenubarSubContent>
            </MenubarSub>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem>Cut</MenubarItem>
            <MenubarItem>Copy</MenubarItem>
            <MenubarItem>Paste</MenubarItem>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent xstyle={styles.content}>
          <MenubarGroup>
            <MenubarCheckboxItem>Bookmarks Bar</MenubarCheckboxItem>
            <MenubarCheckboxItem defaultChecked>Full URLs</MenubarCheckboxItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem inset>
              Reload <MenubarShortcut>⌘R</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled inset>
              Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem inset>Toggle Fullscreen</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem inset>Hide Sidebar</MenubarItem>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Profiles</MenubarTrigger>
        <MenubarContent>
          <MenubarRadioGroup defaultValue="benoit">
            <MenubarRadioItem value="andy">Andy</MenubarRadioItem>
            <MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
            <MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
          </MenubarRadioGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem inset>Edit...</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarItem inset>Add Profile...</MenubarItem>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## Installation

1. Install the following dependencies:

   ```bash
   npm install @base-ui/react @stylexjs/stylex
   ```

2. Set up the token layer and the StyleX compiler from [Installation](https://carbon.style/docs/installation), including `states.ts`, `state-styles.ts`, and `interop.css` for icons. Install [Dropdown Menu](https://carbon.style/docs/components/dropdown-menu) for the shared menu parts.

3. Copy and paste the following code into your project.

   ```tsx title="components/ui/menubar.tsx"
   "use client"

   import type { ComponentProps, CSSProperties } from "react"
   import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"
   import { Menu as MenuPrimitive } from "@base-ui/react/menu"
   import * as stylex from "@stylexjs/stylex"
   import type { StyleXStyles } from "@stylexjs/stylex"
   import { stateStyles } from "@/lib/state-styles"
   import { states } from "@/theme/states"
   import { color, duration, ease, leading, radius, space, text } from "@/theme/tokens.stylex"
   import {
     DropdownMenu,
     DropdownMenuPortal,
     DropdownMenuGroup,
     DropdownMenuItem,
     DropdownMenuLabel,
     DropdownMenuSeparator,
     DropdownMenuShortcut,
     DropdownMenuCheckboxItem,
     DropdownMenuRadioGroup,
     DropdownMenuRadioItem,
     DropdownMenuSub,
     DropdownMenuSubTrigger,
     DropdownMenuSubContent,
     DropdownMenuContent,
   } from "@/components/ui/dropdown-menu"

   const styles = stylex.create({
     root: {
       display: "flex",
       alignItems: "center",
       height: space.s8,
       gap: space.s0_5,
       borderRadius: radius.lg,
       padding: "3px",
     },
     vertical: { flexDirection: "column", height: "auto", alignItems: "stretch" },
     trigger: {
       display: "flex",
       alignItems: "center",
       userSelect: "none",
       borderRadius: `calc(${radius.lg} - 3px)`,
       borderWidth: 1,
       borderStyle: "solid",
       paddingInline: space.s1_5,
       paddingBlock: space.s0_5,
       fontSize: text.sm,
       lineHeight: leading.sm,
       fontWeight: 500,
       backgroundColor: { default: color.transparent, ":hover": color.itemHighlightBg },
       transitionProperty: "color, background-color, border-color, box-shadow",
       transitionDuration: duration.color,
       transitionTimingFunction: ease.standard,
     },
     open: {
       color: color.secondaryForeground,
     },
     content: {
       minWidth: "9rem",
     },
   })
   const menubarStyles = {
     ...styles,
     root: [states.well, styles.root],
     open: [states.key, states.keySurface, states.wellKey, styles.open],
     focusRing: states.focusRing,
   }
   type Overrides = { xstyle?: StyleXStyles; className?: string; style?: CSSProperties }
   function Menubar({
     xstyle,
     className,
     style,
     ...props
   }: Omit<MenubarPrimitive.Props, "className" | "style"> & Overrides) {
     return (
       <MenubarPrimitive
         data-slot="menubar"
         {...props}
         {...stateStyles(
           (state) => [
             states.well,
             styles.root,
             state.orientation === "vertical" && styles.vertical,
             xstyle,
           ],
           { className, style },
         )}
       />
     )
   }
   function MenubarTrigger({
     xstyle,
     className,
     style,
     ...props
   }: Omit<MenuPrimitive.Trigger.Props, "className" | "style"> & Overrides) {
     return (
       <MenuPrimitive.Trigger
         data-slot="menubar-trigger"
         {...props}
         {...stateStyles(
           (state) => [
             styles.trigger,
             states.focusRing,
             state.open && [states.key, states.keySurface, states.wellKey, styles.open],
             state.disabled && states.disabled,
             xstyle,
           ],
           { className, style },
         )}
       />
     )
   }
   function MenubarContent({
     xstyle,
     alignOffset = -4,
     sideOffset = 8,
     ...props
   }: ComponentProps<typeof DropdownMenuContent>) {
     return (
       <DropdownMenuContent
         data-slot="menubar-content"
         alignOffset={alignOffset}
         sideOffset={sideOffset}
         xstyle={[styles.content, xstyle]}
         {...props}
       />
     )
   }

   function MenubarMenu(props: ComponentProps<typeof DropdownMenu>) {
     return <DropdownMenu {...props} />
   }

   function MenubarPortal(props: ComponentProps<typeof DropdownMenuPortal>) {
     return <DropdownMenuPortal {...props} />
   }

   function MenubarGroup(props: ComponentProps<typeof DropdownMenuGroup>) {
     return <DropdownMenuGroup data-slot="menubar-group" {...props} />
   }

   function MenubarItem(props: ComponentProps<typeof DropdownMenuItem>) {
     return <DropdownMenuItem data-slot="menubar-item" {...props} />
   }

   function MenubarLabel(props: ComponentProps<typeof DropdownMenuLabel>) {
     return <DropdownMenuLabel data-slot="menubar-label" {...props} />
   }

   function MenubarSeparator(props: ComponentProps<typeof DropdownMenuSeparator>) {
     return <DropdownMenuSeparator data-slot="menubar-separator" {...props} />
   }

   function MenubarShortcut(props: ComponentProps<typeof DropdownMenuShortcut>) {
     return <DropdownMenuShortcut data-slot="menubar-shortcut" {...props} />
   }

   function MenubarCheckboxItem(props: ComponentProps<typeof DropdownMenuCheckboxItem>) {
     return <DropdownMenuCheckboxItem data-slot="menubar-checkbox-item" {...props} />
   }

   function MenubarRadioGroup(props: ComponentProps<typeof DropdownMenuRadioGroup>) {
     return <DropdownMenuRadioGroup data-slot="menubar-radio-group" {...props} />
   }

   function MenubarRadioItem(props: ComponentProps<typeof DropdownMenuRadioItem>) {
     return <DropdownMenuRadioItem data-slot="menubar-radio-item" {...props} />
   }

   function MenubarSub(props: ComponentProps<typeof DropdownMenuSub>) {
     return <DropdownMenuSub {...props} />
   }

   function MenubarSubTrigger(props: ComponentProps<typeof DropdownMenuSubTrigger>) {
     return <DropdownMenuSubTrigger data-slot="menubar-sub-trigger" {...props} />
   }

   function MenubarSubContent(props: ComponentProps<typeof DropdownMenuSubContent>) {
     return <DropdownMenuSubContent data-slot="menubar-sub-content" {...props} />
   }

   export {
     Menubar,
     MenubarTrigger,
     MenubarContent,
     MenubarMenu,
     MenubarPortal,
     MenubarGroup,
     MenubarItem,
     MenubarLabel,
     MenubarSeparator,
     MenubarShortcut,
     MenubarCheckboxItem,
     MenubarRadioGroup,
     MenubarRadioItem,
     MenubarSub,
     MenubarSubTrigger,
     MenubarSubContent,
     menubarStyles,
   }
   ```

4. Update the import paths to match your project setup.

## Usage

```tsx
import {
  Menubar,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarMenu,
  MenubarSeparator,
  MenubarShortcut,
  MenubarTrigger,
} from "@/components/ui/menubar"
```

```tsx
<Menubar>
  <MenubarMenu>
    <MenubarTrigger>File</MenubarTrigger>
    <MenubarContent>
      <MenubarGroup>
        <MenubarItem>
          New Tab <MenubarShortcut>⌘T</MenubarShortcut>
        </MenubarItem>
        <MenubarItem>New Window</MenubarItem>
      </MenubarGroup>
      <MenubarSeparator />
      <MenubarGroup>
        <MenubarItem>Share</MenubarItem>
        <MenubarItem>Print</MenubarItem>
      </MenubarGroup>
    </MenubarContent>
  </MenubarMenu>
</Menubar>
```

RTL support is not included.

## Composition

Use the following composition to build a `Menubar`:

```text
Menubar
├── MenubarMenu
│   ├── MenubarTrigger
│   └── MenubarContent
│       ├── MenubarGroup
│       │   ├── MenubarLabel
│       │   ├── MenubarItem
│       │   └── MenubarItem
│       ├── MenubarSeparator
│       ├── MenubarGroup
│       │   ├── MenubarLabel
│       │   ├── MenubarCheckboxItem
│       │   └── MenubarCheckboxItem
│       ├── MenubarSeparator
│       ├── MenubarGroup
│       │   ├── MenubarLabel
│       │   └── MenubarRadioGroup
│       │       ├── MenubarRadioItem
│       │       └── MenubarRadioItem
│       └── MenubarSub
│           ├── MenubarSubTrigger
│           └── MenubarSubContent
│               └── MenubarGroup
│                   ├── MenubarLabel
│                   ├── MenubarItem
│                   └── MenubarItem
└── MenubarMenu
    ├── MenubarTrigger
    └── MenubarContent
        └── MenubarGroup
            ├── MenubarLabel
            ├── MenubarItem
            └── MenubarItem
```

## Checkbox

Use `MenubarCheckboxItem` for toggleable options.

```tsx
import * as stylex from "@stylexjs/stylex"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarSeparator,
  MenubarShortcut,
  MenubarTrigger,
} from "@/components/ui/menubar"

const styles = stylex.create({ menubar: { width: "18rem" }, content: { width: "16rem" } })

export default function MenubarCheckbox() {
  return (
    <Menubar xstyle={styles.menubar}>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent xstyle={styles.content}>
          <MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
          <MenubarCheckboxItem defaultChecked>Always Show Full URLs</MenubarCheckboxItem>
          <MenubarSeparator />
          <MenubarItem inset>
            Reload <MenubarShortcut>⌘R</MenubarShortcut>
          </MenubarItem>
          <MenubarItem disabled inset>
            Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Format</MenubarTrigger>
        <MenubarContent>
          <MenubarCheckboxItem defaultChecked>Strikethrough</MenubarCheckboxItem>
          <MenubarCheckboxItem>Code</MenubarCheckboxItem>
          <MenubarCheckboxItem>Superscript</MenubarCheckboxItem>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## Radio

Use `MenubarRadioGroup` and `MenubarRadioItem` for single-select options.

```tsx
"use client"

import * as React from "react"
import * as stylex from "@stylexjs/stylex"

import {
  Menubar,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarTrigger,
} from "@/components/ui/menubar"

const styles = stylex.create({ menubar: { width: "18rem" } })

export default function MenubarRadio() {
  const [user, setUser] = React.useState("benoit")
  const [theme, setTheme] = React.useState("system")

  return (
    <Menubar xstyle={styles.menubar}>
      <MenubarMenu>
        <MenubarTrigger>Profiles</MenubarTrigger>
        <MenubarContent>
          <MenubarRadioGroup value={user} onValueChange={setUser}>
            <MenubarRadioItem value="andy">Andy</MenubarRadioItem>
            <MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
            <MenubarRadioItem value="luis">Luis</MenubarRadioItem>
          </MenubarRadioGroup>
          <MenubarSeparator />
          <MenubarItem inset>Edit...</MenubarItem>
          <MenubarItem inset>Add Profile...</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Theme</MenubarTrigger>
        <MenubarContent>
          <MenubarRadioGroup value={theme} onValueChange={setTheme}>
            <MenubarRadioItem value="light">Light</MenubarRadioItem>
            <MenubarRadioItem value="dark">Dark</MenubarRadioItem>
            <MenubarRadioItem value="system">System</MenubarRadioItem>
          </MenubarRadioGroup>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## Submenu

Use `MenubarSub`, `MenubarSubTrigger`, and `MenubarSubContent` for nested menus.

```tsx
import * as stylex from "@stylexjs/stylex"
import {
  Menubar,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/ui/menubar"

const styles = stylex.create({ menubar: { width: "18rem" } })

export default function MenubarSubmenu() {
  return (
    <Menubar xstyle={styles.menubar}>
      <MenubarMenu>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarSub>
            <MenubarSubTrigger>Share</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>Email link</MenubarItem>
              <MenubarItem>Messages</MenubarItem>
              <MenubarItem>Notes</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem>
            Print... <MenubarShortcut>⌘P</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Edit</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>
            Undo <MenubarShortcut>⌘Z</MenubarShortcut>
          </MenubarItem>
          <MenubarItem>
            Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
          </MenubarItem>
          <MenubarSeparator />
          <MenubarSub>
            <MenubarSubTrigger>Find</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>Find...</MenubarItem>
              <MenubarItem>Find Next</MenubarItem>
              <MenubarItem>Find Previous</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem>Cut</MenubarItem>
          <MenubarItem>Copy</MenubarItem>
          <MenubarItem>Paste</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## With icons

Add icons to `MenubarItem`.

```tsx
import * as stylex from "@stylexjs/stylex"
import {
  FileIcon,
  FolderIcon,
  HelpCircleIcon,
  SaveIcon,
  SettingsIcon,
  TrashIcon,
} from "lucide-react"

import {
  Menubar,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarMenu,
  MenubarSeparator,
  MenubarShortcut,
  MenubarTrigger,
} from "@/components/ui/menubar"

const styles = stylex.create({ menubar: { width: "18rem" } })

export default function MenubarIcons() {
  return (
    <Menubar xstyle={styles.menubar}>
      <MenubarMenu>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>
            <FileIcon />
            New File <MenubarShortcut>⌘N</MenubarShortcut>
          </MenubarItem>
          <MenubarItem>
            <FolderIcon />
            Open Folder
          </MenubarItem>
          <MenubarSeparator />
          <MenubarItem>
            <SaveIcon />
            Save <MenubarShortcut>⌘S</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>More</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              <SettingsIcon />
              Settings
            </MenubarItem>
            <MenubarItem>
              <HelpCircleIcon />
              Help
            </MenubarItem>
            <MenubarSeparator />
            <MenubarItem variant="destructive">
              <TrashIcon />
              Delete
            </MenubarItem>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## API reference

`Menubar` accepts [Base UI Menubar props](https://base-ui.com/react/components/menubar). Menu parts accept their [Dropdown Menu props](https://carbon.style/docs/components/dropdown-menu), including `render`. Styled parts take `xstyle`, `className` and inline `style`.

### MenubarContent

| Prop          | Type                                                                       | Default    |
| ------------- | -------------------------------------------------------------------------- | ---------- |
| `side`        | `"top" \| "bottom" \| "left" \| "right" \| "inline-start" \| "inline-end"` | `"bottom"` |
| `sideOffset`  | `number`                                                                   | `8`        |
| `align`       | `"start" \| "center" \| "end"`                                             | `"start"`  |
| `alignOffset` | `number`                                                                   | `-4`       |

### menubarStyles

| Key         | What it is                                       |
| ----------- | ------------------------------------------------ |
| `root`      | The well and trigger spacing                     |
| `vertical`  | Vertical arrangement                             |
| `trigger`   | Trigger type, nested corner, row-highlight hover |
| `open`      | The raised key while the menu is open            |
| `content`   | Menu minimum width                               |
| `focusRing` | Shared keyboard focus ring                       |

### Data attributes

| Attribute                                               | On            | Effect                         |
| ------------------------------------------------------- | ------------- | ------------------------------ |
| `data-slot="menubar"`                                   | root          | Bar anatomy                    |
| `data-orientation`                                      | root          | Horizontal or vertical         |
| `data-open`, `data-disabled`                            | trigger       | Base UI state                  |
| `data-highlighted`, `data-disabled`, `data-checked`     | items         | Base UI state                  |
| `data-inset`, `data-variant`                            | items         | Item appearance                |
| `data-side`, `data-starting-style`, `data-ending-style` | popup         | Placement and transition state |
| `data-slot="menubar-trigger"`                           | trigger       | Part anatomy                   |
| `data-slot="menubar-content"`                           | content       | Part anatomy                   |
| `data-slot="menubar-group"`                             | group         | Part anatomy                   |
| `data-slot="menubar-item"`                              | item          | Part anatomy                   |
| `data-slot="menubar-label"`                             | label         | Part anatomy                   |
| `data-slot="menubar-separator"`                         | separator     | Part anatomy                   |
| `data-slot="menubar-shortcut"`                          | shortcut      | Part anatomy                   |
| `data-slot="menubar-checkbox-item"`                     | checkbox-item | Part anatomy                   |
| `data-slot="menubar-radio-group"`                       | radio-group   | Part anatomy                   |
| `data-slot="menubar-radio-item"`                        | radio-item    | Part anatomy                   |
| `data-slot="menubar-sub-trigger"`                       | sub-trigger   | Part anatomy                   |
| `data-slot="menubar-sub-content"`                       | sub-content   | Part anatomy                   |

Checkbox and radio indicator spans retain their `dropdown-menu-*-item-indicator` slots. `MenubarMenu`, `MenubarSub` and `MenubarPortal` add no element.
