Menubar

Persistent horizontal menu for top-level actions.

Keep top-level actions in a horizontal menu bar. Each trigger opens its menu on click.

tsx
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 menubar

Usage

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
    └── MenubarContent

Checkbox

Use MenubarCheckboxItem for options that can be toggled independently.

tsx
"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.

tsx
"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>  )}

Nest related actions with MenubarSub, MenubarSubTrigger, and MenubarSubContent. Hover or click the sub trigger to open it.

tsx
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.

tsx
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

Root bar with role="menubar". Only one menu stays open at a time, and each trigger toggles on click.

PropTypeDefault
classNamestring
<Menubar>  <MenubarMenu>    <MenubarTrigger>File</MenubarTrigger>    <MenubarContent>      <MenubarItem>New Tab</MenubarItem>    </MenubarContent>  </MenubarMenu></Menubar>

Groups a trigger with its content. Pass value when you need a stable menu ID.

PropTypeDefault
valuestringauto
<MenubarMenu>  <MenubarTrigger>File</MenubarTrigger>  <MenubarContent>...</MenubarContent></MenubarMenu>

Opens or closes the menu on click.

PropTypeDefault
classNamestring
<MenubarTrigger>File</MenubarTrigger>

Portaled panel under the trigger.

PropTypeDefault
align"start" | "center" | "end""start"
sideOffsetnumber8
alignOffsetnumber-4
<MenubarContent>  <MenubarItem>New Tab</MenubarItem></MenubarContent>
PropTypeDefault
insetbooleanfalse
variant"default" | "destructive""default"
disabledbooleanfalse
<MenubarItem>New Tab</MenubarItem>
PropTypeDefault
checkedbooleanfalse
onCheckedChange(checked: boolean) => void
insetbooleanfalse
<MenubarCheckboxItem checked>  Show bookmarks</MenubarCheckboxItem>
PropTypeDefault
valuestring""
onValueChange(value: string) => void
<MenubarRadioGroup value="jordan">  <MenubarRadioItem value="jordan">Jordan</MenubarRadioItem></MenubarRadioGroup>
PropTypeDefault
valuestring
insetbooleanfalse
<MenubarRadioItem value="jordan">Jordan</MenubarRadioItem>

Layout helpers for labels, separators, keyboard hints, and grouped items.

<MenubarGroup>  <MenubarLabel>Account</MenubarLabel>  <MenubarItem>    Profile    <MenubarShortcut>⌘P</MenubarShortcut>  </MenubarItem>  <MenubarSeparator /></MenubarGroup>

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>