Menubar

A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.

Installation

Install the following dependencies:

npm install @radix-ui/react-menubar

Copy and paste the following code into your project.

'use client';
 
import * as MenubarPrimitive from '@radix-ui/react-menubar';
import clsx from 'clsx';
import { Check, ChevronRight, Circle } from 'lucide-react';
 
import { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, forwardRef } from 'react';
import styles from './styles.module.scss';
 
const MenubarMenu = MenubarPrimitive.Menu;
 
const MenubarGroup = MenubarPrimitive.Group;
 
const MenubarPortal = MenubarPrimitive.Portal;
 
const MenubarSub = MenubarPrimitive.Sub;
 
const MenubarRadioGroup = MenubarPrimitive.RadioGroup;
 
const Menubar = forwardRef<
    ElementRef<typeof MenubarPrimitive.Root>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
>(({ className, ...props }, ref) => (
    <MenubarPrimitive.Root ref={ref} className={clsx(styles.menubar, className)} {...props} />
));
Menubar.displayName = MenubarPrimitive.Root.displayName;
 
const MenubarTrigger = forwardRef<
    ElementRef<typeof MenubarPrimitive.Trigger>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
>(({ className, ...props }, ref) => (
    <MenubarPrimitive.Trigger ref={ref} className={clsx(styles.menubar__trigger, className)} {...props} />
));
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
 
const MenubarSubTrigger = forwardRef<
    ElementRef<typeof MenubarPrimitive.SubTrigger>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
        inset?: boolean;
    }
>(({ className, inset, children, ...props }, ref) => (
    <MenubarPrimitive.SubTrigger
        ref={ref}
        className={clsx(styles.menubar__sub__trigger, inset && styles.menubar__inset, className)}
        {...props}
    >
        {children}
        <ChevronRight className={styles.menubar__sub__trigger__icon} />
    </MenubarPrimitive.SubTrigger>
));
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
 
const MenubarSubContent = forwardRef<
    ElementRef<typeof MenubarPrimitive.SubContent>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
>(({ className, ...props }, ref) => (
    <MenubarPrimitive.SubContent ref={ref} className={clsx(styles.menubar__sub__content, className)} {...props} />
));
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
 
const MenubarContent = forwardRef<
    ElementRef<typeof MenubarPrimitive.Content>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
>(({ className, align = 'start', alignOffset = -4, sideOffset = 8, ...props }, ref) => (
    <MenubarPrimitive.Portal>
        <MenubarPrimitive.Content
            ref={ref}
            align={align}
            alignOffset={alignOffset}
            sideOffset={sideOffset}
            className={clsx(styles.menubar__content, className)}
            {...props}
        />
    </MenubarPrimitive.Portal>
));
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
 
const MenubarItem = forwardRef<
    ElementRef<typeof MenubarPrimitive.Item>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
        inset?: boolean;
    }
>(({ className, inset, ...props }, ref) => (
    <MenubarPrimitive.Item
        ref={ref}
        className={clsx(styles.menubar__item, inset && styles.menubar__inset, className)}
        {...props}
    />
));
MenubarItem.displayName = MenubarPrimitive.Item.displayName;
 
const MenubarCheckboxItem = forwardRef<
    ElementRef<typeof MenubarPrimitive.CheckboxItem>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
    <MenubarPrimitive.CheckboxItem
        ref={ref}
        className={clsx(styles.menubar__checkbox__item, className)}
        checked={checked}
        {...props}
    >
        <span className={styles.menubar__checkbox__item__check}>
            <MenubarPrimitive.ItemIndicator>
                <Check className={styles.menubar__checkbox__item__icon} />
            </MenubarPrimitive.ItemIndicator>
        </span>
        {children}
    </MenubarPrimitive.CheckboxItem>
));
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
 
const MenubarRadioItem = forwardRef<
    ElementRef<typeof MenubarPrimitive.RadioItem>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
    <MenubarPrimitive.RadioItem ref={ref} className={clsx(styles.menubar__radio__item, className)} {...props}>
        <span className={styles.menubar__radio__item__circle}>
            <MenubarPrimitive.ItemIndicator>
                <Circle className={styles.menubar__radio__item__icon} />
            </MenubarPrimitive.ItemIndicator>
        </span>
        {children}
    </MenubarPrimitive.RadioItem>
));
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
 
const MenubarLabel = forwardRef<
    ElementRef<typeof MenubarPrimitive.Label>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
        inset?: boolean;
    }
>(({ className, inset, ...props }, ref) => (
    <MenubarPrimitive.Label
        ref={ref}
        className={clsx(styles.menubar__label, inset && styles.menubar__inset, className)}
        {...props}
    />
));
MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
 
const MenubarSeparator = forwardRef<
    ElementRef<typeof MenubarPrimitive.Separator>,
    ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
>(({ className, ...props }, ref) => (
    <MenubarPrimitive.Separator ref={ref} className={clsx(styles.menubar__separator, className)} {...props} />
));
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
 
const MenubarShortcut = ({ className, ...props }: HTMLAttributes<HTMLSpanElement>) => {
    return <span className={clsx(styles.menubar__shortcut, className)} {...props} />;
};
MenubarShortcut.displayname = 'MenubarShortcut';
 
export {
    Menubar,
    MenubarCheckboxItem,
    MenubarContent,
    MenubarGroup,
    MenubarItem,
    MenubarLabel,
    MenubarMenu,
    MenubarPortal,
    MenubarRadioGroup,
    MenubarRadioItem,
    MenubarSeparator,
    MenubarShortcut,
    MenubarSub,
    MenubarSubContent,
    MenubarSubTrigger,
    MenubarTrigger,
};

Update the import paths to match your project setup.

Usage

import {
    Menubar,
    MenubarContent,
    MenubarItem,
    MenubarMenu,
    MenubarSeparator,
    MenubarShortcut,
    MenubarTrigger,
} from '@/components/ui/menubar';
<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>
</Menubar>