Menubar
A horizontal menu bar component for React and Next.js applications. Perfect for desktop-style interfaces with File, Edit, View menus and keyboard shortcuts.
Remember those classic desktop apps with File, Edit, View menus across the top? That's what menubars do - give your web app that familiar desktop feel with persistent navigation and keyboard shortcuts.
Classic desktop menubar
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 with full keyboard navigation, screen reader support, and all the interaction patterns users expect from desktop apps.
npx shadcn@latest add menubar
Why menubars work for certain apps
Not every app needs a menubar, but when you're building something that feels like desktop software, they're perfect:
- Familiar patterns - Users know where to find File, Edit, View menus
- Keyboard shortcuts - Show and handle common shortcuts like ⌘S, ⌘C
- Persistent access - Always visible, never hidden behind hamburger menus
- Professional feel - Makes web apps feel more like "real" software
- Organized actions - Logical grouping of related functionality
- Space efficient - Pack lots of functionality without clutter
Essential menubar patterns
Simple menu structure
Basic File, Edit, View setup:
"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 settings:
"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,}
Great for desktop-style web apps
Works best when you're building something that feels like traditional desktop software - text editors, IDEs, design tools, productivity apps. The menubar gives users that familiar navigation they're used to.
Drop it into any React or Next.js app where you want that professional, desktop-app aesthetic.
API Reference
Menubar
The root container that holds all menu groups.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | MenubarMenu components |
MenubarMenu
Individual menu group (like "File" or "Edit").
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | MenubarTrigger and MenubarContent |
MenubarTrigger
The clickable menu label that opens the dropdown.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Menu label text |
MenubarContent
The dropdown content that appears when menu is opened.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
align | "start" | "center" | "end" | "start" | Alignment relative to trigger |
side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side to open |
sideOffset | number | 8 | Distance from trigger |
children | React.ReactNode | - | Menu items and separators |
MenubarItem
Individual clickable menu item.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
disabled | boolean | false | Whether item is disabled |
inset | boolean | false | Add left padding for alignment |
onSelect | (event: Event) => void | - | Callback when item is selected |
children | React.ReactNode | - | Item content and shortcuts |
MenubarCheckboxItem
Menu item with checkbox for toggleable options.
Prop | Type | Default | Description |
---|---|---|---|
checked | boolean | "indeterminate" | - | Checkbox state |
onCheckedChange | (checked: boolean) => void | - | Callback when checkbox changes |
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Item content |
MenubarRadioItem
Menu item for single-choice selections within a radio group.
Prop | Type | Default | Description |
---|---|---|---|
value | string | - | Unique value for this radio option |
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Item content |
MenubarShortcut
Display keyboard shortcuts in menu items.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Shortcut text (e.g., "⌘S") |
MenubarSeparator
Visual separator between menu sections.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes |
Keyboard Navigation
Key | Action |
---|---|
Tab | Move focus to next menubar item |
Shift + Tab | Move focus to previous menubar item |
Enter / Space | Open focused menu |
Arrow Down | Open menu or move to next item |
Arrow Up | Move to previous menu item |
Arrow Left | Move to previous menubar menu |
Arrow Right | Move to next menubar menu |
Escape | Close menu and return to menubar |
A-Z | Focus item starting with typed letter |
Common Menu Types
Menu | Typical Items | Use Cases |
---|---|---|
File | New, Open, Save, Print, Export | Document operations |
Edit | Undo, Redo, Cut, Copy, Paste, Find | Content editing |
View | Zoom, Layout, Sidebar, Fullscreen | Display options |
Tools | Settings, Preferences, Extensions | Utilities |
Help | Documentation, About, Support | User assistance |
Build menubars that make sense
- Follow conventions - Put File first, Help last, Edit and View in between
- Group logically - Related actions go together, separated by dividers
- Show shortcuts - Teach users faster ways to work
- Keep it simple - Don't nest menus more than 2-3 levels deep
- Make items scannable - Clear labels, consistent terminology
- Handle states - Show what's selected, enabled, disabled
- Test keyboard nav - Make sure everything works without a mouse
Label
Accessible form labels for React and Next.js applications. Built with Radix UI and styled with Tailwind CSS for perfect shadcn/ui integration.
Navigation Menu
A collection of links for navigating websites and React applications. Built with Radix UI NavigationMenu for keyboard navigation and screen reader accessibility.