- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Card
- Checkbox
- Collapsible
- Combobox
- Context Menu
- Date Picker (Lite)
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP (Lite)
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarGroup,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar"
export default function MenubarDemo() {
return (
<Menubar class="w-72">
<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 class="w-44">
<MenubarGroup>
<MenubarCheckboxItem>Bookmarks Bar</MenubarCheckboxItem>
<MenubarCheckboxItem checked>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 value="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
pnpm dlx shadcnui-hono-jsx@latest add menubarnpx shadcnui-hono-jsx@latest add menubaryarn dlx shadcnui-hono-jsx@latest add menubarbunx shadcnui-hono-jsx@latest add menubarThis component uses a small client script. add installs it into public/shadcn/; serve that directory at /shadcn/ and load the script on pages that use the component (see Client Scripts):
<script type="module" src="/shadcn/menu.js"></script>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
Use the following composition to build a Menubar:
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
└── MenubarItemCheckbox
Use MenubarCheckboxItem for toggleable options.
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarTrigger,
} from "@/components/ui/menubar"
export function MenubarCheckbox() {
return (
<Menubar class="w-72">
<MenubarMenu>
<MenubarTrigger>View</MenubarTrigger>
<MenubarContent class="w-64">
<MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
<MenubarCheckboxItem checked>
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 checked>Strikethrough</MenubarCheckboxItem>
<MenubarCheckboxItem>Code</MenubarCheckboxItem>
<MenubarCheckboxItem>Superscript</MenubarCheckboxItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
)
}Radio
Use MenubarRadioGroup and MenubarRadioItem for single-select options.
import {
Menubar,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarTrigger,
} from "@/components/ui/menubar"
export function MenubarRadio() {
return (
<Menubar class="w-72">
<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 />
<MenubarItem inset>Edit...</MenubarItem>
<MenubarItem inset>Add Profile...</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Theme</MenubarTrigger>
<MenubarContent>
<MenubarRadioGroup defaultValue="system">
<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.
import {
Menubar,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar"
export function MenubarSubmenu() {
return (
<Menubar class="w-72">
<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
import {
FileIcon,
FolderIcon,
HelpCircleIcon,
SaveIcon,
SettingsIcon,
TrashIcon,
} from "@/components/icons"
import {
Menubar,
MenubarContent,
MenubarGroup,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarTrigger,
} from "@/components/ui/menubar"
export function MenubarIcons() {
return (
<Menubar class="w-72">
<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>
)
}RTL
To enable RTL support in shadcn/ui, see the RTL configuration guide.
// This example sets dir and uses useTranslation because this site is not RTL.
// In an RTL app you won't need them; see the RTL guide.
import {
type Translations,
useTranslation,
} from "@/components/language-selector"
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarGroup,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar"
const translations: Translations = {
en: {
dir: "ltr",
values: {
file: "File",
newTab: "New Tab",
newWindow: "New Window",
newIncognitoWindow: "New Incognito Window",
share: "Share",
emailLink: "Email link",
messages: "Messages",
notes: "Notes",
print: "Print...",
edit: "Edit",
undo: "Undo",
redo: "Redo",
find: "Find",
searchTheWeb: "Search the web",
findItem: "Find...",
findNext: "Find Next",
findPrevious: "Find Previous",
cut: "Cut",
copy: "Copy",
paste: "Paste",
view: "View",
bookmarksBar: "Bookmarks Bar",
fullUrls: "Full URLs",
reload: "Reload",
forceReload: "Force Reload",
toggleFullscreen: "Toggle Fullscreen",
hideSidebar: "Hide Sidebar",
profiles: "Profiles",
andy: "Andy",
benoit: "Benoit",
luis: "Luis",
editProfile: "Edit...",
addProfile: "Add Profile...",
},
},
ar: {
dir: "rtl",
values: {
file: "ملف",
newTab: "علامة تبويب جديدة",
newWindow: "نافذة جديدة",
newIncognitoWindow: "نافذة التصفح المتخفي الجديدة",
share: "مشاركة",
emailLink: "رابط البريد الإلكتروني",
messages: "الرسائل",
notes: "الملاحظات",
print: "طباعة...",
edit: "تعديل",
undo: "تراجع",
redo: "إعادة",
find: "بحث",
searchTheWeb: "البحث على الويب",
findItem: "بحث...",
findNext: "البحث التالي",
findPrevious: "البحث السابق",
cut: "قص",
copy: "نسخ",
paste: "لصق",
view: "عرض",
bookmarksBar: "شريط الإشارات المرجعية",
fullUrls: "عناوين URL الكاملة",
reload: "إعادة تحميل",
forceReload: "إعادة تحميل قسري",
toggleFullscreen: "تبديل وضع ملء الشاشة",
hideSidebar: "إخفاء الشريط الجانبي",
profiles: "الملفات الشخصية",
andy: "Andy",
benoit: "Benoit",
luis: "Luis",
editProfile: "تعديل...",
addProfile: "إضافة ملف شخصي...",
},
},
he: {
dir: "rtl",
values: {
file: "קובץ",
newTab: "כרטיסייה חדשה",
newWindow: "חלון חדש",
newIncognitoWindow: "חלון גלישה בסתר חדש",
share: "שתף",
emailLink: "קישור אימייל",
messages: "הודעות",
notes: "הערות",
print: "הדפס...",
edit: "ערוך",
undo: "בטל",
redo: "בצע שוב",
find: "מצא",
searchTheWeb: "חפש באינטרנט",
findItem: "מצא...",
findNext: "מצא הבא",
findPrevious: "מצא הקודם",
cut: "גזור",
copy: "העתק",
paste: "הדבק",
view: "תצוגה",
bookmarksBar: "סרגל סימניות",
fullUrls: "כתובות URL מלאות",
reload: "רענן",
forceReload: "רענן בכוח",
toggleFullscreen: "החלף מסך מלא",
hideSidebar: "הסתר סרגל צד",
profiles: "פרופילים",
andy: "Andy",
benoit: "Benoit",
luis: "Luis",
editProfile: "ערוך...",
addProfile: "הוסף פרופיל...",
},
},
}
export function MenubarRtl() {
const { dir, t, language } = useTranslation(translations, "ar")
return (
<Menubar class="w-72" dir={dir}>
<MenubarMenu>
<MenubarTrigger>{t.file}</MenubarTrigger>
<MenubarContent dir={dir} align={dir === "rtl" ? "end" : "start"}>
<MenubarGroup>
<MenubarItem>
{t.newTab} <MenubarShortcut>⌘T</MenubarShortcut>
</MenubarItem>
<MenubarItem>
{t.newWindow} <MenubarShortcut>⌘N</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>{t.newIncognitoWindow}</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarSub>
<MenubarSubTrigger>{t.share}</MenubarSubTrigger>
<MenubarSubContent
dir={dir}
data-lang={dir === "rtl" ? language : undefined}
>
<MenubarGroup>
<MenubarItem>{t.emailLink}</MenubarItem>
<MenubarItem>{t.messages}</MenubarItem>
<MenubarItem>{t.notes}</MenubarItem>
</MenubarGroup>
</MenubarSubContent>
</MenubarSub>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem>
{t.print} <MenubarShortcut>⌘P</MenubarShortcut>
</MenubarItem>
</MenubarGroup>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>{t.edit}</MenubarTrigger>
<MenubarContent
dir={dir}
align={dir === "rtl" ? "end" : "start"}
data-lang={dir === "rtl" ? language : undefined}
>
<MenubarGroup>
<MenubarItem>
{t.undo} <MenubarShortcut>⌘Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
{t.redo} <MenubarShortcut>⇧⌘Z</MenubarShortcut>
</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarSub>
<MenubarSubTrigger>{t.find}</MenubarSubTrigger>
<MenubarSubContent
dir={dir}
data-lang={dir === "rtl" ? language : undefined}
>
<MenubarGroup>
<MenubarItem>{t.searchTheWeb}</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem>{t.findItem}</MenubarItem>
<MenubarItem>{t.findNext}</MenubarItem>
<MenubarItem>{t.findPrevious}</MenubarItem>
</MenubarGroup>
</MenubarSubContent>
</MenubarSub>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem>{t.cut}</MenubarItem>
<MenubarItem>{t.copy}</MenubarItem>
<MenubarItem>{t.paste}</MenubarItem>
</MenubarGroup>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>{t.view}</MenubarTrigger>
<MenubarContent
class="w-44"
dir={dir}
align={dir === "rtl" ? "end" : "start"}
data-lang={dir === "rtl" ? language : undefined}
>
<MenubarGroup>
<MenubarCheckboxItem>{t.bookmarksBar}</MenubarCheckboxItem>
<MenubarCheckboxItem checked>{t.fullUrls}</MenubarCheckboxItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem inset>
{t.reload} <MenubarShortcut>⌘R</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled inset>
{t.forceReload} <MenubarShortcut>⇧⌘R</MenubarShortcut>
</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem inset>{t.toggleFullscreen}</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem inset>{t.hideSidebar}</MenubarItem>
</MenubarGroup>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>{t.profiles}</MenubarTrigger>
<MenubarContent
dir={dir}
align={dir === "rtl" ? "end" : "start"}
data-lang={dir === "rtl" ? language : undefined}
>
<MenubarRadioGroup defaultValue="benoit">
<MenubarRadioItem value="andy">{t.andy}</MenubarRadioItem>
<MenubarRadioItem value="benoit">{t.benoit}</MenubarRadioItem>
<MenubarRadioItem value="Luis">{t.luis}</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem inset>{t.editProfile}</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem inset>{t.addProfile}</MenubarItem>
</MenubarGroup>
</MenubarContent>
</MenubarMenu>
</Menubar>
)
}Notes
- The menu is a native popover placed with CSS anchor positioning, so it opens without JavaScript (placement needs Chrome 135, Firefox 147 or Safari 26.2). The client script
/shadcn/menu.js(<script type="module" src="/shadcn/menu.js">) adds the menu behavior: focus handling, arrow keys, typeahead, checkbox and radio items, submenus and closing after a choice. - Items have no
onClickon the server: userenderfor links (render={<a href="/settings" />}) or form buttons. Controlled state (open,onOpenChange,checked/onCheckedChange,value/onValueChange),modal(page scroll is not locked) andopenOnHoveron the root are not supported. - Moving between menus with the arrow keys and switching menus by hovering while one is open need the client script
/shadcn/menu.js(<script type="module" src="/shadcn/menu.js">); without it each menu still opens with its trigger.modalis not supported. - Accepts
classinstead ofclassName. - Upstream documentation: shadcn/ui Menubar. See also Differences from shadcn/ui.
API Reference
See the Base UI Menubar documentation.