suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
GitHubGet started
DocsComponentsPatternsInteractionsChartsBlocks
Components82
  • Overview
  • Accordion
  • Alert
  • Alert Dialog
  • Alert Sheet
  • Amount Input
  • Aspect Ratio
  • Attachment
  • Avatar
  • Badge
  • Bottom Bar
  • Breadcrumb
  • Bubble
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Chip
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • FAB
  • Field
  • Fullscreen Menu
  • Haptics
  • Header
  • Hover Card
  • Icon
  • Input
  • Input Accessory Bar
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Keyboard Scroll View
  • Keypad
  • Label
  • Marker
  • Menubar
  • Message
  • Message Scroller
  • Native Select
  • Navigation Menu
  • Page Indicator
  • Pagination
  • Pin Pad
  • Popover
  • Progress
  • QR Scanner
  • Questionnaire
  • Radio Group
  • Resizable
  • Screen
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Signature Pad
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Tab Bar
  • Table
  • Tabs
  • Text
  • Textarea
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip
  • Wheel Picker
  • Widget

suiss/ui · Component

Menubar

A horizontal bar of menus, like a desktop application's menu bar.

Menubar is an open-source component from suiss/ui for React. The @esuiss/ui CLI copies its source into your project, so you own the code.

Menubar wraps the menubar primitive of the chosen base and groups several menus into one keyboard-navigable bar. Each MenubarMenu holds a MenubarTrigger and a MenubarContent popup. Inside the content, compose MenubarItem, MenubarCheckboxItem, MenubarRadioGroup with MenubarRadioItem, MenubarLabel, MenubarGroup, MenubarSeparator, MenubarShortcut, and nested submenus built from MenubarSub, MenubarSubTrigger and MenubarSubContent.

Most parts reuse the Dropdown Menu components with menubar styling. Use Menubar for persistent, app-level command menus; use Dropdown Menu for a single menu opened from one button.

Installation

CLI

$ pnpm dlx shadcn@latest add @esuiss/menubar

Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add menubar

Manual

  1. Install the dependencies and add the cn helper:
$ pnpm add @base-ui/react @phosphor-icons/react
  1. Add the pieces it builds on: Dropdown Menu.

  2. Copy the source into components/ui/menubar.tsx:

  1. Update the import paths to match your project.

Usage

import { Menubar, MenubarMenu, MenubarGroup, MenubarPortal, MenubarTrigger, MenubarContent, MenubarItem, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarLabel, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubTrigger, MenubarSubContent } 
<div



Each MenubarMenu accepts the menu root props, such as open, defaultOpen and onOpenChange. MenubarItem also accepts variant="destructive" and inset. Checkbox items use checked/defaultChecked, and radio groups use value/defaultValue. Pass disabled on Menubar to disable the whole bar, or on an individual item.

MenubarContent defaults to align="start", alignOffset={-4} and sideOffset={8}. MenubarShortcut accepts mod to prepend the platform modifier key.

Examples

By default

The File menu opened on first render with defaultOpen, including a Share submenu.

Disabled

A menubar with disabled set, so none of its menus open.

API Reference

01

Menubar

The bar that contains the menus and manages keyboard navigation between them.

Also accepts the props of the primitive part it wraps.

02

MenubarMenu

Groups one trigger with its popup and holds that menu's open state.

Also accepts the props of React.ComponentProps<typeof DropdownMenu>.

03

MenubarGroup

Groups related items inside a menu.

Also accepts the props of React.ComponentProps<typeof DropdownMenuGroup>.

04

MenubarPortal

Renders menu content into a portal outside the bar.

Also accepts the props of React.ComponentProps<typeof DropdownMenuPortal>.

05

MenubarTrigger

The button in the bar that opens its menu.

Also accepts the props of React.ComponentProps<typeof DropdownMenuTrigger>.

06

MenubarContent

The positioned popup that holds a menu's items.

Also accepts the props of React.ComponentProps<typeof DropdownMenuContent>.

07

MenubarItem

A single command in a menu.

Also accepts the props of React.ComponentProps<typeof DropdownMenuItem>.

08

MenubarCheckboxItem

An item that toggles on and off, with a leading check indicator.

PropTypeDefaultDescription
insetboolean-Sets data-inset on the item for inset alignment.

Also accepts the props of the primitive part it wraps.

09

MenubarRadioGroup

Groups radio items so only one can be selected.

Also accepts the props of React.ComponentProps<typeof DropdownMenuRadioGroup>.

10

MenubarRadioItem

One option in a radio group, with a leading check indicator when selected.

PropTypeDefaultDescription
insetboolean-Sets data-inset on the item for inset alignment.

Also accepts the props of the primitive part it wraps.

11

MenubarLabel

A non-interactive heading for a section of items.

PropTypeDefaultDescription
insetboolean-Indents the label to align with items that show a leading icon or indicator.

Also accepts the props of React.ComponentProps<typeof DropdownMenuLabel>.

12

MenubarSeparator

A thin divider between groups of items.

Also accepts the props of React.ComponentProps<typeof DropdownMenuSeparator>.

13

MenubarShortcut

A trailing keyboard shortcut hint inside an item.

Also accepts the props of React.ComponentProps<typeof DropdownMenuShortcut>.

14

MenubarSub

The root of a nested submenu.

Also accepts the props of React.ComponentProps<typeof DropdownMenuSub>.

15

MenubarSubTrigger

The item that opens a submenu.

PropTypeDefaultDescription
insetboolean-Indents the trigger to align with items that show a leading icon or indicator.

Also accepts the props of React.ComponentProps<typeof DropdownMenuSubTrigger>.

16

MenubarSubContent

The popup that holds a submenu's items.

Also accepts the props of React.ComponentProps<typeof DropdownMenuSubContent>.

Accessibility

  • The bar has the menubar role and each trigger has the menuitem role, with aria-expanded reflecting its menu's state.
  • Popups use the menu role; items use menuitem, menuitemcheckbox or menuitemradio, with aria-checked on checkbox and radio items.
  • While a menu is open, ArrowLeft and ArrowRight move to the adjacent menu. ArrowRight on a submenu trigger opens the submenu.
  • Escape closes the open menu and returns focus to its trigger.
  • Disabled items expose aria-disabled="true".

Notes

  • Styling hooks: each part sets a data-slot such as menubar, menubar-trigger, menubar-content, menubar-item and menubar-sub-trigger. Items expose data-variant and data-inset.
  • Checkbox and radio items always reserve leading space for their indicator.
  • MenubarShortcut is hidden below the md breakpoint.
  • Uses the popover, accent, destructive and border colors.
NextMessagePreviousMarker

On this page

  1. 01Installation
    • CLI
    • Manual
  2. 02Usage
  3. 03Examples
    • By default
    • Disabled
  4. 04API Reference
    • Menubar
    • MenubarMenu
    • MenubarGroup
    • MenubarPortal
    • MenubarTrigger
    • MenubarContent
    • MenubarItem
    • MenubarCheckboxItem
    • MenubarRadioGroup
    • MenubarRadioItem
    • MenubarLabel
    • MenubarSeparator
    • MenubarShortcut
    • MenubarSub
    • MenubarSubTrigger
    • MenubarSubContent
  5. 05Accessibility
  6. 06Notes
from
"@/components/ui/menubar"
className
=
"min-h-96"
>
<Menubar>
<MenubarExample />
</Menubar>
</div>
import {
  ClipboardTextIcon,
  CopyIcon,
  ScissorsIcon,
  TrashIcon,
} from "@phosphor-icons/react"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarLabel,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/ui/menubar"

function MenubarExample({ fileOpen = false }: { fileOpen?: boolean }) {
  return (
    <>
      <MenubarMenu defaultOpen={fileOpen}>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              New tab
              <MenubarShortcut mod>T</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              New window
              <MenubarShortcut mod>N</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled>New private window</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarSub>
            <MenubarSubTrigger>Share</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>Email link</MenubarItem>
              <MenubarItem>Messages</MenubarItem>
              <MenubarItem>Notes</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem>
            Print
            <MenubarShortcut mod>P</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Edit</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              <ScissorsIcon />
              Cut
              <MenubarShortcut mod>X</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <CopyIcon />
              Copy
              <MenubarShortcut mod>C</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <ClipboardTextIcon />
              Paste
              <MenubarShortcut mod>V</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem variant="destructive">
            <TrashIcon />
            Delete
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarCheckboxItem defaultChecked>
              Show bookmarks bar
            </MenubarCheckboxItem>
            <MenubarCheckboxItem>Show full URLs</MenubarCheckboxItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Reload</MenubarItem>
          <MenubarItem inset>Toggle full screen</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Profiles</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarLabel>Switch profile</MenubarLabel>
            <MenubarRadioGroup defaultValue="alex">
              <MenubarRadioItem value="alex">Alex</MenubarRadioItem>
              <MenubarRadioItem value="sam">Sam</MenubarRadioItem>
              <MenubarRadioItem value="taylor">Taylor</MenubarRadioItem>
            </MenubarRadioGroup>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Manage profiles</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
    </>
  )
}

export default function MenubarDemo() {
  return (
    <div className="min-h-96">
      <Menubar>
        <MenubarExample />
      </Menubar>
    </div>
  )
}
components/ui/menubar.tsx
"use client"

import { Menu as MenuPrimitive } from "@base-ui/react/menu"
import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"
import { CheckIcon } from "@phosphor-icons/react"
import type * as React from "react"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuPortal,
  DropdownMenuRadioGroup,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
import {
  ClipboardTextIcon,
  CopyIcon,
  ScissorsIcon,
  TrashIcon,
} from "@phosphor-icons/react"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarLabel,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/ui/menubar"

function MenubarExample({ fileOpen = false }: { fileOpen?: boolean }) {
  return (
    <>
      <MenubarMenu defaultOpen={fileOpen}>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              New tab
              <MenubarShortcut mod>T</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              New window
              <MenubarShortcut mod>N</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled>New private window</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarSub>
            <MenubarSubTrigger>Share</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>Email link</MenubarItem>
              <MenubarItem>Messages</MenubarItem>
              <MenubarItem>Notes</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem>
            Print
            <MenubarShortcut mod>P</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Edit</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              <ScissorsIcon />
              Cut
              <MenubarShortcut mod>X</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <CopyIcon />
              Copy
              <MenubarShortcut mod>C</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <ClipboardTextIcon />
              Paste
              <MenubarShortcut mod>V</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem variant="destructive">
            <TrashIcon />
            Delete
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarCheckboxItem defaultChecked>
              Show bookmarks bar
            </MenubarCheckboxItem>
            <MenubarCheckboxItem>Show full URLs</MenubarCheckboxItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Reload</MenubarItem>
          <MenubarItem inset>Toggle full screen</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Profiles</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarLabel>Switch profile</MenubarLabel>
            <MenubarRadioGroup defaultValue="alex">
              <MenubarRadioItem value="alex">Alex</MenubarRadioItem>
              <MenubarRadioItem value="sam">Sam</MenubarRadioItem>
              <MenubarRadioItem value="taylor">Taylor</MenubarRadioItem>
            </MenubarRadioGroup>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Manage profiles</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
    </>
  )
}

export default function MenubarDisabled() {
  return (
    <div className="min-h-96">
      <Menubar disabled>
        <MenubarExample />
      </Menubar>
    </div>
  )
}
import {
  ClipboardTextIcon,
  CopyIcon,
  ScissorsIcon,
  TrashIcon,
} from "@phosphor-icons/react"
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarGroup,
  MenubarItem,
  MenubarLabel,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from "@/components/ui/menubar"

function MenubarExample({ fileOpen = false }: { fileOpen?: boolean }) {
  return (
    <>
      <MenubarMenu defaultOpen={fileOpen}>
        <MenubarTrigger>File</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              New tab
              <MenubarShortcut mod>T</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              New window
              <MenubarShortcut mod>N</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled>New private window</MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarSub>
            <MenubarSubTrigger>Share</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>Email link</MenubarItem>
              <MenubarItem>Messages</MenubarItem>
              <MenubarItem>Notes</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem>
            Print
            <MenubarShortcut mod>P</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Edit</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarItem>
              <ScissorsIcon />
              Cut
              <MenubarShortcut mod>X</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <CopyIcon />
              Copy
              <MenubarShortcut mod>C</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <ClipboardTextIcon />
              Paste
              <MenubarShortcut mod>V</MenubarShortcut>
            </MenubarItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem variant="destructive">
            <TrashIcon />
            Delete
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>View</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarCheckboxItem defaultChecked>
              Show bookmarks bar
            </MenubarCheckboxItem>
            <MenubarCheckboxItem>Show full URLs</MenubarCheckboxItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Reload</MenubarItem>
          <MenubarItem inset>Toggle full screen</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Profiles</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarLabel>Switch profile</MenubarLabel>
            <MenubarRadioGroup defaultValue="alex">
              <MenubarRadioItem value="alex">Alex</MenubarRadioItem>
              <MenubarRadioItem value="sam">Sam</MenubarRadioItem>
              <MenubarRadioItem value="taylor">Taylor</MenubarRadioItem>
            </MenubarRadioGroup>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarItem inset>Manage profiles</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
    </>
  )
}

export default function MenubarOpenByDefault() {
  return (
    <div className="min-h-96">
      <Menubar>
        <MenubarExample fileOpen />
      </Menubar>
    </div>
  )
}