Shadcn Menubar
React menubar for desktop-style menu bars with keyboard shortcuts. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.
Menubar navigation broken?
Join our Discord community for help from other developers.
Ever built a web app that felt too much like a website and not enough like real software? Or tried to cram complex functionality into hamburger menus where users can never find anything? Yeah, that's exactly when you need a proper menubar. This shadcn/ui menubar brings that familiar desktop application feel to your React applications.
Menubar showcase
Complete menubar with submenus, shortcuts, and toggles:
"use client"import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarDemo() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem> New Tab <MenubarShortcut>⌘T</MenubarShortcut> </MenubarItem> <MenubarItem> New Window <MenubarShortcut>⌘N</MenubarShortcut> </MenubarItem> <MenubarItem disabled>New Incognito Window</MenubarItem> <MenubarSeparator /> <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>Search the web</MenubarItem> <MenubarSeparator /> <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> <MenubarMenu> <MenubarTrigger>View</MenubarTrigger> <MenubarContent> <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> <MenubarSeparator /> <MenubarItem inset>Toggle Fullscreen</MenubarItem> <MenubarSeparator /> <MenubarItem inset>Hide Sidebar</MenubarItem> </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 /> <MenubarItem inset>Edit...</MenubarItem> <MenubarSeparator /> <MenubarItem inset>Add Profile...</MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
Built on Radix UI Menubar primitives with full keyboard navigation, screen reader support, and all the interaction patterns users expect from professional desktop software. Styled with Tailwind CSS so it matches your design system instead of looking like a generic system menu.
npx shadcn@latest add menubar
Why menubars actually work for complex applications
Here's the thing—not every app needs a menubar, but when you're building something that feels like desktop software, they're essential. Think about VS Code, Figma, or Notion. These apps have complex functionality that needs logical organization. A hamburger menu would be a disaster.
Users expect File, Edit, View menus because they've been using desktop apps for decades. When you put "Save" under File and "Copy" under Edit, they don't have to think—muscle memory takes over. That's the power of following established patterns instead of reinventing navigation.
This free shadcn menubar handles the complex parts—keyboard shortcuts, nested submenus, focus management, accessibility—while you focus on organizing your app's functionality. Whether you're building text editors, design tools, or productivity applications in your Next.js projects, menubars that follow desktop conventions make your web apps feel professional in your JavaScript applications.
Common menubar patterns you'll actually use
Simple menu structure
Basic File, Edit, View setup that works:
"use client"import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarSimple() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem> New Tab <MenubarShortcut>⌘T</MenubarShortcut> </MenubarItem> <MenubarItem>New Window</MenubarItem> <MenubarSeparator /> <MenubarItem>Share</MenubarItem> <MenubarSeparator /> <MenubarItem>Print</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Edit</MenubarTrigger> <MenubarContent> <MenubarItem>Undo</MenubarItem> <MenubarItem>Redo</MenubarItem> <MenubarSeparator /> <MenubarItem>Cut</MenubarItem> <MenubarItem>Copy</MenubarItem> <MenubarItem>Paste</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>View</MenubarTrigger> <MenubarContent> <MenubarItem>Zoom In</MenubarItem> <MenubarItem>Zoom Out</MenubarItem> <MenubarSeparator /> <MenubarItem>Fullscreen</MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
With keyboard shortcuts
Show shortcuts to teach users faster workflows:
"use client"import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarWithShortcuts() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem> New <MenubarShortcut>⌘N</MenubarShortcut> </MenubarItem> <MenubarItem> Open <MenubarShortcut>⌘O</MenubarShortcut> </MenubarItem> <MenubarItem> Save <MenubarShortcut>⌘S</MenubarShortcut> </MenubarItem> <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 /> <MenubarItem> Cut <MenubarShortcut>⌘X</MenubarShortcut> </MenubarItem> <MenubarItem> Copy <MenubarShortcut>⌘C</MenubarShortcut> </MenubarItem> <MenubarItem> Paste <MenubarShortcut>⌘V</MenubarShortcut> </MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
Checkbox toggles
Perfect for view options and feature toggles:
"use client"import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarWithCheckboxes() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>View</MenubarTrigger> <MenubarContent> <MenubarCheckboxItem checked>Show Sidebar</MenubarCheckboxItem> <MenubarCheckboxItem>Show Status Bar</MenubarCheckboxItem> <MenubarCheckboxItem checked>Show Toolbar</MenubarCheckboxItem> <MenubarSeparator /> <MenubarCheckboxItem>Word Wrap</MenubarCheckboxItem> <MenubarCheckboxItem checked>Show Line Numbers</MenubarCheckboxItem> <MenubarSeparator /> <MenubarItem>Zoom In</MenubarItem> <MenubarItem>Zoom Out</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Window</MenubarTrigger> <MenubarContent> <MenubarCheckboxItem>Always on Top</MenubarCheckboxItem> <MenubarCheckboxItem checked>Show in Dock</MenubarCheckboxItem> <MenubarSeparator /> <MenubarItem>Minimize</MenubarItem> <MenubarItem>Close</MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
Nested submenus
Organize complex actions hierarchically:
"use client"import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarWithSubmenu() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>File</MenubarTrigger> <MenubarContent> <MenubarItem>New</MenubarItem> <MenubarItem>Open</MenubarItem> <MenubarSeparator /> <MenubarSub> <MenubarSubTrigger>Export</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Export as PDF</MenubarItem> <MenubarItem>Export as Image</MenubarItem> <MenubarItem>Export as HTML</MenubarItem> <MenubarSeparator /> <MenubarSub> <MenubarSubTrigger>More formats</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Word Document</MenubarItem> <MenubarItem>PowerPoint</MenubarItem> <MenubarItem>Excel Spreadsheet</MenubarItem> </MenubarSubContent> </MenubarSub> </MenubarSubContent> </MenubarSub> <MenubarSeparator /> <MenubarItem>Print</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Tools</MenubarTrigger> <MenubarContent> <MenubarSub> <MenubarSubTrigger>Developer Tools</MenubarSubTrigger> <MenubarSubContent> <MenubarItem>Console</MenubarItem> <MenubarItem>Network</MenubarItem> <MenubarItem>Sources</MenubarItem> <MenubarSeparator /> <MenubarItem>Performance</MenubarItem> <MenubarItem>Memory</MenubarItem> </MenubarSubContent> </MenubarSub> <MenubarItem>Extensions</MenubarItem> <MenubarItem>Settings</MenubarItem> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
Radio button groups
Single-choice options like themes or layouts:
"use client"import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarTrigger,} from "@/components/ui/menubar"export default function MenubarWithRadio() { return ( <div className="flex justify-center"> <Menubar> <MenubarMenu> <MenubarTrigger>Theme</MenubarTrigger> <MenubarContent> <MenubarRadioGroup value="system"> <MenubarRadioItem value="light">Light</MenubarRadioItem> <MenubarRadioItem value="dark">Dark</MenubarRadioItem> <MenubarRadioItem value="system">System</MenubarRadioItem> </MenubarRadioGroup> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Layout</MenubarTrigger> <MenubarContent> <MenubarRadioGroup value="comfortable"> <MenubarRadioItem value="compact">Compact</MenubarRadioItem> <MenubarRadioItem value="comfortable">Comfortable</MenubarRadioItem> <MenubarRadioItem value="spacious">Spacious</MenubarRadioItem> </MenubarRadioGroup> <MenubarSeparator /> <MenubarItem>Reset to Default</MenubarItem> </MenubarContent> </MenubarMenu> <MenubarMenu> <MenubarTrigger>Language</MenubarTrigger> <MenubarContent> <MenubarRadioGroup value="english"> <MenubarRadioItem value="english">English</MenubarRadioItem> <MenubarRadioItem value="spanish">Español</MenubarRadioItem> <MenubarRadioItem value="french">Français</MenubarRadioItem> <MenubarRadioItem value="german">Deutsch</MenubarRadioItem> </MenubarRadioGroup> </MenubarContent> </MenubarMenu> </Menubar> </div> )}
"use client"import * as React from "react"import * as MenubarPrimitive from "@radix-ui/react-menubar"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { cn } from "@/lib/utils"function Menubar({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Root>) { return ( <MenubarPrimitive.Root data-slot="menubar" className={cn( "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs", className )} {...props} /> )}function MenubarMenu({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />}function MenubarGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Group>) { return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />}function MenubarPortal({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />}function MenubarRadioGroup({ ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { return ( <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> )}function MenubarTrigger({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { return ( <MenubarPrimitive.Trigger data-slot="menubar-trigger" className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none", className )} {...props} /> )}function MenubarContent({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props}: React.ComponentProps<typeof MenubarPrimitive.Content>) { return ( <MenubarPortal> <MenubarPrimitive.Content data-slot="menubar-content" align={align} alignOffset={alignOffset} sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md", className )} {...props} /> </MenubarPortal> )}function MenubarItem({ className, inset, variant = "default", ...props}: React.ComponentProps<typeof MenubarPrimitive.Item> & { inset?: boolean variant?: "default" | "destructive"}) { return ( <MenubarPrimitive.Item data-slot="menubar-item" data-inset={inset} data-variant={variant} className={cn( "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} /> )}function MenubarCheckboxItem({ className, children, checked, ...props}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { return ( <MenubarPrimitive.CheckboxItem data-slot="menubar-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} checked={checked} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CheckIcon className="size-4" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.CheckboxItem> )}function MenubarRadioItem({ className, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { return ( <MenubarPrimitive.RadioItem data-slot="menubar-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} > <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <MenubarPrimitive.ItemIndicator> <CircleIcon className="size-2 fill-current" /> </MenubarPrimitive.ItemIndicator> </span> {children} </MenubarPrimitive.RadioItem> )}function MenubarLabel({ className, inset, ...props}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean}) { return ( <MenubarPrimitive.Label data-slot="menubar-label" data-inset={inset} className={cn( "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className )} {...props} /> )}function MenubarSeparator({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.Separator>) { return ( <MenubarPrimitive.Separator data-slot="menubar-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> )}function MenubarShortcut({ className, ...props}: React.ComponentProps<"span">) { return ( <span data-slot="menubar-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", className )} {...props} /> )}function MenubarSub({ ...props}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />}function MenubarSubTrigger({ className, inset, children, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean}) { return ( <MenubarPrimitive.SubTrigger data-slot="menubar-sub-trigger" data-inset={inset} className={cn( "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className )} {...props} > {children} <ChevronRightIcon className="ml-auto h-4 w-4" /> </MenubarPrimitive.SubTrigger> )}function MenubarSubContent({ className, ...props}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { return ( <MenubarPrimitive.SubContent data-slot="menubar-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className )} {...props} /> )}export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent,}
Features
This free open source menubar component includes everything you need:
- TypeScript-first - Full type safety with menu events and state management
- Radix UI powered - Battle-tested accessibility and keyboard navigation
- Desktop conventions - Familiar File, Edit, View menu patterns users expect
- Tailwind CSS styled - Customize with utilities, not fighting component CSS
- Keyboard shortcuts - Display and handle common shortcuts like ⌘S, ⌘C
- Nested submenus - Organize complex functionality hierarchically
- Interactive elements - Checkboxes, radio groups, and disabled states
- Professional feel - Makes web apps feel like real desktop software
API Reference
Core Components
Component | Purpose | Key Props |
---|---|---|
Menubar | Root container | Groups all menu sections |
MenubarMenu | Individual menu group | Contains trigger and content |
MenubarTrigger | Menu label button | Opens dropdown on click/focus |
MenubarContent | Dropdown content | Contains items and separators |
Menu Items
Component | Purpose | Use Case |
---|---|---|
MenubarItem | Basic menu action | Save, Copy, Delete actions |
MenubarCheckboxItem | Toggle option | Show sidebar, Enable feature |
MenubarRadioItem | Single choice | Theme selection, View mode |
MenubarSeparator | Visual divider | Group related actions |
MenubarShortcut | Keyboard hint | Display ⌘S, Ctrl+C shortcuts |
Common Menu Types
Menu | Typical Actions | Purpose |
---|---|---|
File | New, Open, Save, Export | Document operations |
Edit | Undo, Cut, Copy, Paste | Content manipulation |
View | Zoom, Layout, Sidebar | Display options |
Tools | Settings, Preferences | Utilities and configuration |
Production tips
Follow desktop conventions religiously. This free shadcn/ui menubar works best when you stick to patterns users already know. File goes first, Help goes last, Edit and View in between. This TypeScript component provides the structure—you provide the familiar organization that matches user expectations in your Next.js applications.
Group actions logically with separators. Related functionality should be grouped together with visual separators between different types of actions. This open source shadcn component supports separators—use them to create scannable menu sections that make sense.
Show keyboard shortcuts strategically. Don't show shortcuts for everything—focus on common actions users perform repeatedly. This JavaScript component displays shortcuts beautifully, but restraint creates cleaner menus in your React applications.
Keep nesting shallow. More than 2-3 levels of nested menus gets confusing and hard to navigate. The Tailwind CSS styled component supports any depth, but cognitive load matters more than technical capability.
Handle states clearly. Show what's selected, enabled, or disabled with consistent visual indicators. Users should understand the current state at a glance. This component provides the state management—you provide clear visual feedback.
Integration with other components
Menubars naturally work with Button components for toolbar actions that complement menu functionality in your React applications. Use Separator components to organize complex menu sections visually.
For desktop-style interfaces, combine menubars with Tabs components for document switching or Dialog components for settings and preferences. This open source pattern creates cohesive desktop application experiences.
When building text editors or design tools, pair menubars with ContextMenu components—menubar for application-level actions, context menu for object-specific actions. Tooltip components work well for explaining complex menu items.
For status indicators, use menubars with Badge components to show counts or Switch components for feature toggles. Your JavaScript application can compose these shadcn components while maintaining desktop application conventions.
Questions you might have
Shadcn Label
React label component for accessible form labels with semantic HTML and form association. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.
Shadcn Navigation Menu
React navigation menu component for website navigation with dropdowns and mega menus. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.