Keep top-level actions in a horizontal menu bar. Each trigger opens its menu on click.
import { Menubar, MenubarContent, MenubarGroup, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger,} from "@/components/ui/menubar"function RefreshIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={className} > <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" /> <path d="M21 3v5h-5" /> <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" /> <path d="M8 16H3v5" /> </svg> )}function MaximizeIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={className} > <path d="M8 3H5a2 2 0 0 0-2 2v3" /> <path d="M21 8V5a2 2 0 0 0-2-2h-3" /> <path d="M3 16v3a2 2 0 0 0 2 2h3" /> <path d="M16 21h3a2 2 0 0 0 2-2v-3" /> </svg> )}export function Example() { return ( <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> <MenubarMenu> <MenubarTrigger>Edit</MenubarTrigger> <MenubarContent> <MenubarItem> Undo <MenubarShortcut>⌘Z</MenubarShortcut> </MenubarItem> <MenubarItem> Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut> </MenubarItem> <MenubarSeparator /> <MenubarItem>Cut</MenubarItem> <MenubarItem>Copy</MenubarItem> <MenubarItem>Paste</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>View</MenubarTrigger> <MenubarContent> <MenubarItem> <RefreshIcon /> Reload </MenubarItem> <MenubarItem disabled> <RefreshIcon /> Force Reload </MenubarItem> <MenubarSeparator /> <MenubarItem> <MaximizeIcon /> Toggle Fullscreen </MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Profiles</MenubarTrigger> <MenubarContent> <MenubarItem>Alex</MenubarItem> <MenubarItem>Jordan</MenubarItem> <MenubarItem>Sam</MenubarItem> <MenubarSeparator /> <MenubarItem>Edit…</MenubarItem> <MenubarSeparator /> <MenubarItem>Add Profile…</MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> )}Installation
npx @arctis-sh/@arctis-sh/ui@latest add menubarUsage
import { Menubar, MenubarContent, MenubarGroup, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger,} from "@/components/ui/menubar"<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>Composition
Menubar
├── MenubarMenu
│ ├── MenubarTrigger
│ └── MenubarContent
│ ├── MenubarGroup
│ │ ├── MenubarLabel
│ │ ├── MenubarItem
│ │ └── MenubarItem
│ ├── MenubarSeparator
│ ├── MenubarCheckboxItem
│ ├── MenubarRadioGroup
│ │ └── MenubarRadioItem
│ └── MenubarSub
│ ├── MenubarSubTrigger
│ └── MenubarSubContent
│ └── MenubarItem
└── MenubarMenu
├── MenubarTrigger
└── MenubarContentCheckbox
Use MenubarCheckboxItem for options that can be toggled independently.
"use client"import { useState } from "react"import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarLabel, MenubarMenu, MenubarSeparator, MenubarTrigger,} from "@/components/ui/menubar"export function Example() { const [showBookmarks, setShowBookmarks] = useState(true) const [showUrls, setShowUrls] = useState(false) const [wrapLines, setWrapLines] = useState(true) const [showWhitespace, setShowWhitespace] = useState(false) return ( <Menubar> <MenubarMenu> <MenubarTrigger>View</MenubarTrigger> <MenubarContent> <MenubarLabel>Appearance</MenubarLabel> <MenubarSeparator /> <MenubarCheckboxItem checked={showBookmarks} onCheckedChange={setShowBookmarks} > Show Bookmarks Bar </MenubarCheckboxItem> <MenubarCheckboxItem checked={showUrls} onCheckedChange={setShowUrls}> Show Full URLs </MenubarCheckboxItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Format</MenubarTrigger> <MenubarContent> <MenubarCheckboxItem checked={wrapLines} onCheckedChange={setWrapLines} > Wrap Lines </MenubarCheckboxItem> <MenubarCheckboxItem checked={showWhitespace} onCheckedChange={setShowWhitespace} > Show Whitespace </MenubarCheckboxItem> </MenubarContent> </MenubarMenu> </Menubar> )}Radio
Use MenubarRadioGroup and MenubarRadioItem when only one choice can be active.
"use client"import { useState } from "react"import { Menubar, MenubarContent, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarTrigger,} from "@/components/ui/menubar"export function Example() { const [profile, setProfile] = useState("alex") const [theme, setTheme] = useState("system") return ( <Menubar> <MenubarMenu> <MenubarTrigger>Profiles</MenubarTrigger> <MenubarContent> <MenubarLabel>Account</MenubarLabel> <MenubarSeparator /> <MenubarRadioGroup value={profile} onValueChange={setProfile}> <MenubarRadioItem value="alex">Alex</MenubarRadioItem> <MenubarRadioItem value="jordan">Jordan</MenubarRadioItem> <MenubarRadioItem value="sam">Sam</MenubarRadioItem> </MenubarRadioGroup> </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
Nest related actions with MenubarSub, MenubarSubTrigger, and MenubarSubContent. Hover or click the sub trigger to open it.
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger,} from "@/components/ui/menubar"export function Example() { return ( <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem> New Tab <MenubarShortcut>⌘T</MenubarShortcut> </MenubarItem> <MenubarSub> <MenubarSubTrigger>Share</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Email link</MenubarItem> <MenubarItem>Messages</MenubarItem> <MenubarItem>Notes</MenubarItem> </MenubarSubContent> </MenubarSub> <MenubarSeparator /> <MenubarItem>Print…</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Edit</MenubarTrigger> <MenubarContent> <MenubarItem>Find…</MenubarItem> <MenubarSub> <MenubarSubTrigger>Find</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Search the web…</MenubarItem> <MenubarSeparator /> <MenubarItem>Find…</MenubarItem> <MenubarItem>Find Next</MenubarItem> <MenubarItem>Find Previous</MenubarItem> </MenubarSubContent> </MenubarSub> </MenubarContent> </MenubarMenu> </Menubar> )}With icons
Place icons inside MenubarItem; their sizing matches the rest of the menu.
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger,} from "@/components/ui/menubar"function FileIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={className} > <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /> <path d="M14 2v4a2 2 0 0 0 2 2h4" /> </svg> )}function FolderIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={className} > <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9l-.81-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" /> </svg> )}function MoreHorizontalIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={className} > <circle cx="12" cy="12" r="1" /> <circle cx="19" cy="12" r="1" /> <circle cx="5" cy="12" r="1" /> </svg> )}export function Example() { return ( <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem> <FileIcon /> New File <MenubarShortcut>⌘N</MenubarShortcut> </MenubarItem> <MenubarItem> <FolderIcon /> New Folder </MenubarItem> <MenubarSeparator /> <MenubarItem> <MoreHorizontalIcon /> More… </MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>More</MenubarTrigger> <MenubarContent> <MenubarItem> <MoreHorizontalIcon /> Preferences </MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> )}API Reference
Menubar
Root bar with role="menubar". Only one menu stays open at a time, and each trigger toggles on click.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem>New Tab</MenubarItem> </MenubarContent> </MenubarMenu></Menubar>MenubarMenu
Groups a trigger with its content. Pass value when you need a stable menu ID.
| Prop | Type | Default |
|---|---|---|
| value | string | auto |
<MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent>...</MenubarContent></MenubarMenu>MenubarTrigger
Opens or closes the menu on click.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<MenubarTrigger>File</MenubarTrigger>MenubarContent
Portaled panel under the trigger.
| Prop | Type | Default |
|---|---|---|
| align | "start" | "center" | "end" | "start" |
| sideOffset | number | 8 |
| alignOffset | number | -4 |
<MenubarContent> <MenubarItem>New Tab</MenubarItem></MenubarContent>MenubarItem
| Prop | Type | Default |
|---|---|---|
| inset | boolean | false |
| variant | "default" | "destructive" | "default" |
| disabled | boolean | false |
<MenubarItem>New Tab</MenubarItem>MenubarCheckboxItem
| Prop | Type | Default |
|---|---|---|
| checked | boolean | false |
| onCheckedChange | (checked: boolean) => void | — |
| inset | boolean | false |
<MenubarCheckboxItem checked> Show bookmarks</MenubarCheckboxItem>MenubarRadioGroup
| Prop | Type | Default |
|---|---|---|
| value | string | "" |
| onValueChange | (value: string) => void | — |
<MenubarRadioGroup value="jordan"> <MenubarRadioItem value="jordan">Jordan</MenubarRadioItem></MenubarRadioGroup>MenubarRadioItem
| Prop | Type | Default |
|---|---|---|
| value | string | — |
| inset | boolean | false |
<MenubarRadioItem value="jordan">Jordan</MenubarRadioItem>MenubarLabel / MenubarSeparator / MenubarShortcut / MenubarGroup
Layout helpers for labels, separators, keyboard hints, and grouped items.
<MenubarGroup> <MenubarLabel>Account</MenubarLabel> <MenubarItem> Profile <MenubarShortcut>⌘P</MenubarShortcut> </MenubarItem> <MenubarSeparator /></MenubarGroup>MenubarSub / MenubarSubTrigger / MenubarSubContent
Nested menu. Sub content opens to the right of the sub trigger on hover or click.
<MenubarSub> <MenubarSubTrigger>Share</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Email</MenubarItem> </MenubarSubContent></MenubarSub>