Menubar
A persistent application menu that groups commands into keyboard-navigable menus.
Preview
Example code
Usage
tsx
import {
Menubar,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "earthling-ui/menubar";
export function Example() {
return (
<>
<Menubar>
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem>New document</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Share</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Copy link</MenubarItem>
</MenubarSubContent>
</MenubarSub>
</MenubarContent>
</MenubarMenu>
</Menubar>
</>
);
}
- Use menubars for app-like command sets, not as the primary navigation for a website.
- Group related commands and mirror familiar platform ordering when users expect it.
- Radio and checkbox items communicate persistent settings better than regular menu items.
Installation
Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.
Import package
Own the source
bash
npm install earthling-uiUse the component import shown above. Package updates keep the implementation current.
API reference
Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.
tsx
// Generated by dts-bundle-generator v9.5.1
import * as MenubarPrimitive from '@radix-ui/react-menubar';
import { ComponentProps } from 'react';
export declare function Menubar({ className, ...props }: ComponentProps<typeof MenubarPrimitive.Root>): import("react").JSX.Element;
export declare function MenubarMenu({ ...props }: ComponentProps<typeof MenubarPrimitive.Menu>): import("react").JSX.Element;
export declare function MenubarGroup({ ...props }: ComponentProps<typeof MenubarPrimitive.Group>): import("react").JSX.Element;
export declare function MenubarPortal({ ...props }: ComponentProps<typeof MenubarPrimitive.Portal>): import("react").JSX.Element;
export declare function MenubarTrigger({ className, ...props }: ComponentProps<typeof MenubarPrimitive.Trigger>): import("react").JSX.Element;
export declare function MenubarContent({ className, align, alignOffset, sideOffset, ...props }: ComponentProps<typeof MenubarPrimitive.Content>): import("react").JSX.Element;
export declare function MenubarItem({ className, inset, variant, ...props }: ComponentProps<typeof MenubarPrimitive.Item> & {
inset?: boolean;
variant?: "default" | "destructive";
}): import("react").JSX.Element;
export declare function MenubarCheckboxItem({ className, children, checked, ...props }: ComponentProps<typeof MenubarPrimitive.CheckboxItem>): import("react").JSX.Element;
export declare function MenubarRadioGroup({ ...props }: ComponentProps<typeof MenubarPrimitive.RadioGroup>): import("react").JSX.Element;
export declare function MenubarRadioItem({ className, children, ...props }: ComponentProps<typeof MenubarPrimitive.RadioItem>): import("react").JSX.Element;
export declare function MenubarLabel({ className, inset, ...props }: ComponentProps<typeof MenubarPrimitive.Label> & {
inset?: boolean;
}): import("react").JSX.Element;
export declare function MenubarSeparator({ className, ...props }: ComponentProps<typeof MenubarPrimitive.Separator>): import("react").JSX.Element;
export declare function MenubarShortcut({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
export declare function MenubarSub({ ...props }: ComponentProps<typeof MenubarPrimitive.Sub>): import("react").JSX.Element;
export declare function MenubarSubTrigger({ className, inset, children, ...props }: ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
inset?: boolean;
}): import("react").JSX.Element;
export declare function MenubarSubContent({ className, ...props }: ComponentProps<typeof MenubarPrimitive.SubContent>): import("react").JSX.Element;
export {};Runtime dependencies: @radix-ui/react-menubar, cnfast.
Source
Use the eject command to copy this implementation with its required helpers and project-specific imports.
View Menubar implementation
tsx
"use client";
import * as MenubarPrimitive from "@radix-ui/react-menubar";
import { cn } from "@/utils/cn";
import type { ComponentProps } from "react";
function Menubar({
className,
...props
}: ComponentProps<typeof MenubarPrimitive.Root>) {
return (
<MenubarPrimitive.Root
data-slot="menubar"
className={cn(
"flex h-10 items-center gap-1 rounded-xl border bg-background p-1 shadow-xs",
className,
)}
{...props}
/>
);
}
function MenubarMenu({
...props
}: ComponentProps<typeof MenubarPrimitive.Menu>) {
return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />;
}
function MenubarGroup({
...props
}: ComponentProps<typeof MenubarPrimitive.Group>) {
return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />;
}
function MenubarPortal({
...props
}: ComponentProps<typeof MenubarPrimitive.Portal>) {
return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />;
}
function MenubarTrigger({
className,
...props
}: ComponentProps<typeof MenubarPrimitive.Trigger>) {
return (
<MenubarPrimitive.Trigger
data-slot="menubar-trigger"
className={cn(
"flex cursor-pointer items-center rounded-lg px-2 py-1 text-sm font-medium outline-hidden select-none focus:bg-muted focus:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground",
className,
)}
{...props}
/>
);
}
function MenubarContent({
className,
align = "start",
alignOffset = -4,
sideOffset = 8,
...props
}: ComponentProps<typeof MenubarPrimitive.Content>) {
return (
<MenubarPrimitive.Portal>
<MenubarPrimitive.Content
data-slot="menubar-content"
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
className={cn(
"bg-background text-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 max-h-(--radix-menubar-content-available-height) min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-xl border p-1 shadow-md duration-150 ease-out motion-reduce:animate-none",
className,
)}
{...props}
/>
</MenubarPrimitive.Portal>
);
}
function MenubarItem({
className,
inset,
variant = "default",
...props
}: 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-muted focus:text-foreground data-[variant=destructive]:text-bad data-[variant=destructive]:focus:bg-bad/10 data-[variant=destructive]:focus:text-bad relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:ps-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
/>
);
}
function MenubarCheckboxItem({
className,
children,
checked,
...props
}: ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
return (
<MenubarPrimitive.CheckboxItem
data-slot="menubar-checkbox-item"
className={cn(
"focus:bg-muted focus:text-foreground relative flex cursor-default items-center gap-2 rounded-lg py-1.5 pe-2 ps-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
checked={checked}
{...props}
>
<span className="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<i className="size-4 icon-[lucide--check]" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.CheckboxItem>
);
}
function MenubarRadioGroup({
...props
}: ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
return (
<MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
);
}
function MenubarRadioItem({
className,
children,
...props
}: ComponentProps<typeof MenubarPrimitive.RadioItem>) {
return (
<MenubarPrimitive.RadioItem
data-slot="menubar-radio-item"
className={cn(
"focus:bg-muted focus:text-foreground relative flex cursor-default items-center gap-2 rounded-lg py-1.5 pe-2 ps-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<i className="size-2 fill-current icon-[lucide--circle]" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.RadioItem>
);
}
function MenubarLabel({
className,
inset,
...props
}: 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]:ps-8",
className,
)}
{...props}
/>
);
}
function MenubarSeparator({
className,
...props
}: ComponentProps<typeof MenubarPrimitive.Separator>) {
return (
<MenubarPrimitive.Separator
data-slot="menubar-separator"
className={cn("bg-muted -mx-1 my-1 h-px", className)}
{...props}
/>
);
}
function MenubarShortcut({ className, ...props }: ComponentProps<"span">) {
return (
<span
data-slot="menubar-shortcut"
className={cn(
"text-muted-foreground ms-auto text-xs tracking-widest",
className,
)}
{...props}
/>
);
}
function MenubarSub({ ...props }: ComponentProps<typeof MenubarPrimitive.Sub>) {
return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
}
function MenubarSubTrigger({
className,
inset,
children,
...props
}: ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
inset?: boolean;
}) {
return (
<MenubarPrimitive.SubTrigger
data-slot="menubar-sub-trigger"
data-inset={inset}
className={cn(
"focus:bg-muted focus:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground flex cursor-default items-center rounded-lg px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:ps-8",
className,
)}
{...props}
>
{children}
<i className="ms-auto size-4 icon-[lucide--chevron-right] rtl:rotate-180" />
</MenubarPrimitive.SubTrigger>
);
}
function MenubarSubContent({
className,
...props
}: ComponentProps<typeof MenubarPrimitive.SubContent>) {
return (
<MenubarPrimitive.SubContent
data-slot="menubar-sub-content"
className={cn(
"bg-background text-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 max-h-(--radix-menubar-content-available-height) min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-xl border p-1 shadow-lg duration-150 ease-out motion-reduce:animate-none",
className,
)}
{...props}
/>
);
}
export {
Menubar,
MenubarMenu,
MenubarGroup,
MenubarPortal,
MenubarTrigger,
MenubarContent,
MenubarItem,
MenubarCheckboxItem,
MenubarRadioGroup,
MenubarRadioItem,
MenubarLabel,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubTrigger,
MenubarSubContent,
};