Docs
Menu
Menu
Displays a menu to the user — such as a set of actions or functions — triggered by a button.
🚧 Under development
Installation
Copy and paste the following code into your project.
"use client"
import * as React from "react"
import { Menu as MenuPrimitive } from "@base-ui-components/react/menu"
import { Check, ChevronRight, Circle } from "lucide-react"
import { cn } from "@/lib/utils"
const Menu = MenuPrimitive.Root
const MenuTrigger = MenuPrimitive.Trigger
const MenuGroup = MenuPrimitive.Group
const MenuPortal = MenuPrimitive.Portal
const MenuRadioGroup = MenuPrimitive.RadioGroup
const MenuPositioner = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.Positioner>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Positioner>
>(({ className, sideOffset = 4, ...props }, ref) => (
<MenuPrimitive.Positioner
ref={ref}
className={cn("outline-0", className)}
sideOffset={sideOffset}
{...props}
/>
))
MenuPositioner.displayName = MenuPrimitive.Positioner.displayName
const MenuPopup = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.Popup>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Popup>
>(({ className, ...props }, ref) => (
<MenuPrimitive.Popup
ref={ref}
className={cn(
"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] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md",
className,
)}
{...props}
/>
))
MenuPopup.displayName = MenuPrimitive.Popup.displayName
const MenuItem = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item> & {
inset?: boolean
}
>(({ className, inset, ...props }, ref) => (
<MenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
inset && "pl-8",
className,
)}
{...props}
/>
))
MenuItem.displayName = MenuPrimitive.Item.displayName
const MenuSubmenuTrigger = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.SubmenuTrigger>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubmenuTrigger> & {
inset?: boolean
}
>(({ className, inset, children, ...props }, ref) => (
<MenuPrimitive.SubmenuTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
inset && "pl-8",
className,
)}
{...props}
>
{children}
<ChevronRight className="ml-auto" />
</MenuPrimitive.SubmenuTrigger>
))
MenuSubmenuTrigger.displayName = MenuPrimitive.SubmenuTrigger.displayName
const MenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<MenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-md py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenuPrimitive.CheckboxItemIndicator>
<Check className="h-4 w-4" />
</MenuPrimitive.CheckboxItemIndicator>
</span>
{children}
</MenuPrimitive.CheckboxItem>
))
MenuCheckboxItem.displayName = MenuPrimitive.CheckboxItem.displayName
const MenuRadioItem = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<MenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-md py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenuPrimitive.RadioItemIndicator>
<Circle className="h-2 w-2 fill-current" />
</MenuPrimitive.RadioItemIndicator>
</span>
{children}
</MenuPrimitive.RadioItem>
))
MenuRadioItem.displayName = MenuPrimitive.RadioItem.displayName
const MenuGroupLabel = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.GroupLabel>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.GroupLabel> & {
inset?: boolean
}
>(({ className, inset, ...props }, ref) => (
<MenuPrimitive.GroupLabel
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className,
)}
{...props}
/>
))
MenuGroupLabel.displayName = MenuPrimitive.GroupLabel.displayName
const MenuSeparator = React.forwardRef<
React.ElementRef<typeof MenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<MenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
MenuSeparator.displayName = MenuPrimitive.Separator.displayName
const MenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
MenuShortcut.displayName = "MenuShortcut"
export {
Menu,
MenuTrigger,
MenuPositioner,
MenuPopup,
MenuItem,
MenuCheckboxItem,
MenuRadioItem,
MenuGroupLabel,
MenuSeparator,
MenuShortcut,
MenuGroup,
MenuPortal,
MenuSubmenuTrigger,
MenuRadioGroup,
}
Update the import paths to match your project setup.
Usage
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/menu"
<DropdownMenu>
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>