Dropdown Menu
Add an accessible dropdown menu in React with items, checkboxes, radio groups, and submenus. Built on Radix UI keyboard nav. Install via the shadcn CLI.
What it is & when to use
Dropdown Menu is an accessible menu triggered by a button, built on Radix UI's dropdown-menu primitive. It supports plain items, checkbox items, radio groups, nested submenus, labels, separators, and keyboard shortcuts, with optional inset spacing for alignment. Use it for action menus, account switchers, and command surfaces where users pick an option. Radix provides keyboard navigation, typeahead, focus management, and correct ARIA roles out of the box.
Browse all OverlayPreview
Switch between light and dark to inspect the embedded Storybook preview.
Installation
pnpm dlx shadcn@latest add https://ui.vllnt.com/r/dropdown-menu.jsonStorybook
Explore all variants, controls, and accessibility checks in the interactive Storybook playground.
View in StorybookCode
"use client";
import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { cn } from "../../lib/utils";
const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = ({
children,
className,
inset,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean;
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>>;
}) => (
<DropdownMenuPrimitive.SubTrigger
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className,
)}
ref={reference}
{...props}
>
{children}
<span className="ml-auto text-xs">›</span>
</DropdownMenuPrimitive.SubTrigger>
);
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = ({
className,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> & {
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>>;
}) => (
<DropdownMenuPrimitive.SubContent
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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",
className,
)}
ref={reference}
{...props}
/>
);
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = ({
className,
ref: reference,
sideOffset = 4,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> & {
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.Content>>;
}) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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",
className,
)}
ref={reference}
sideOffset={sideOffset}
{...props}
/>
</DropdownMenuPrimitive.Portal>
);
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = ({
className,
inset,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean;
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.Item>>;
}) => (
<DropdownMenuPrimitive.Item
className={cn(
"relative flex cursor-default select-none items-center rounded-sm 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",
inset && "pl-8",
className,
)}
ref={reference}
{...props}
/>
);
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = ({
checked,
children,
className,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & {
ref?: React.Ref<
React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>
>;
}) => (
<DropdownMenuPrimitive.CheckboxItem
checked={checked}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm 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,
)}
ref={reference}
{...props}
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<span className="text-xs">✓</span>
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
);
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = ({
children,
className,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> & {
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>>;
}) => (
<DropdownMenuPrimitive.RadioItem
className={cn(
"relative flex cursor-default select-none items-center rounded-sm 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,
)}
ref={reference}
{...props}
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<span className="text-xs">○</span>
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
);
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = ({
className,
inset,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean;
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.Label>>;
}) => (
<DropdownMenuPrimitive.Label
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className,
)}
ref={reference}
{...props}
/>
);
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = ({
className,
ref: reference,
...props
}: React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> & {
ref?: React.Ref<React.ComponentRef<typeof DropdownMenuPrimitive.Separator>>;
}) => (
<DropdownMenuPrimitive.Separator
className={cn("-m-1 h-px bg-muted", className)}
ref={reference}
{...props}
/>
);
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
);
};
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
};
Frequently asked questions
- What is Dropdown Menu?
- Dropdown Menu is an accessible menu component for React that opens from a trigger button. Built on Radix UI, it supports items, checkbox items, radio groups, submenus, labels, separators, and shortcuts.
- How do I add Dropdown Menu?
- Run `pnpm dlx shadcn@latest add https://ui.vllnt.com/r/dropdown-menu.json` to install it into your project via the shadcn CLI.
- Is Dropdown Menu keyboard accessible?
- Yes. It is built on Radix UI's dropdown-menu primitive, which handles keyboard navigation, typeahead, focus management, and ARIA roles, including nested submenus and checkbox and radio items.