Dropdown Menu
Menu surfaced from a trigger, built on Radix primitives.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Open menu</Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-48"> <DropdownMenuLabel>Actions</DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuItem>Settings</DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Usage
import { Button } from "@reva/ui";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@reva/ui";Composition
Use the following composition to build a DropdownMenu:
DropdownMenu
├── DropdownMenuTrigger
└── DropdownMenuContent
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ ├── DropdownMenuItem
│ └── DropdownMenuItem
├── DropdownMenuSeparator
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ ├── DropdownMenuCheckboxItem
│ └── DropdownMenuCheckboxItem
├── DropdownMenuSeparator
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ └── DropdownMenuRadioGroup
│ ├── DropdownMenuRadioItem
│ └── DropdownMenuRadioItem
└── DropdownMenuSub
├── DropdownMenuSubTrigger
└── DropdownMenuSubContent
└── DropdownMenuGroup
├── DropdownMenuLabel
├── DropdownMenuItem
└── DropdownMenuItemExamples
Basic
A DropdownMenuLabel followed by DropdownMenuItem rows. Use DropdownMenuSeparator to break unrelated groups, and disabled to grey out an item.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Open</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Settings</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuItem>GitHub</DropdownMenuItem> <DropdownMenuItem>Support</DropdownMenuItem> <DropdownMenuItem disabled>API</DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Icons
Place a Phosphor icon as the first child of DropdownMenuItem — the item applies the correct gap and icon size automatically.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Open</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem> <User /> Profile </DropdownMenuItem> <DropdownMenuItem> <CreditCard /> Billing </DropdownMenuItem> <DropdownMenuItem> <Gear /> Settings </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <SignOut /> Log out </DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Shortcuts
Add keyboard hints with DropdownMenuShortcut — it floats to the trailing edge of the item.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Open</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Billing <DropdownMenuShortcut>⌘B</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Settings <DropdownMenuShortcut>⌘S</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> Log out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Submenu
Nest secondary actions inside DropdownMenuSub with DropdownMenuSubTrigger and DropdownMenuSubContent — the submenu portals to keep stacking contexts clean.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Open</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuItem>Email</DropdownMenuItem> <DropdownMenuItem>Message</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem>More…</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuItem> New Team <DropdownMenuShortcut>⌘T</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Destructive
Set variant="destructive" on DropdownMenuItem to flag actions that cannot be undone — text and focus background switch to the destructive token.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Actions</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem> <PencilSimple /> Edit </DropdownMenuItem> <DropdownMenuItem> <Share /> Share </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem> <Archive /> Archive </DropdownMenuItem> <DropdownMenuItem variant="destructive"> <Trash /> Delete </DropdownMenuItem> </DropdownMenuContent></DropdownMenu>Checkboxes
Toggle independent boolean state with DropdownMenuCheckboxItem. Pass checked and onCheckedChange exactly like Checkbox.
function CheckboxesDemo() { const [showStatusBar, setShowStatusBar] = React.useState(true); const [showActivityBar, setShowActivityBar] = React.useState(false); const [showPanel, setShowPanel] = React.useState(false); return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Checkboxes</Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-44"> <DropdownMenuLabel>Appearance</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar} > Status Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} disabled > Activity Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}> Panel </DropdownMenuCheckboxItem> </DropdownMenuContent> </DropdownMenu> );}Checkboxes with Icons
Combine icons with DropdownMenuCheckboxItem. The check indicator stays at the trailing edge while the leading icon sits before the label.
function CheckboxesIconsDemo() { const [notifications, setNotifications] = React.useState({ email: true, sms: false, push: true, }); return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Notifications</Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-56"> <DropdownMenuLabel>Notification Preferences</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={notifications.email} onCheckedChange={(checked) => setNotifications({ ...notifications, email: checked === true }) } > <Envelope /> Email notifications </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.sms} onCheckedChange={(checked) => setNotifications({ ...notifications, sms: checked === true }) } > <ChatCenteredText /> SMS notifications </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.push} onCheckedChange={(checked) => setNotifications({ ...notifications, push: checked === true }) } > <Bell /> Push notifications </DropdownMenuCheckboxItem> </DropdownMenuContent> </DropdownMenu> );}Radio Group
Mutually-exclusive selection with DropdownMenuRadioGroup and DropdownMenuRadioItem. The group owns the value; items render the dot indicator when selected.
function RadioDemo() { const [position, setPosition] = React.useState("bottom"); return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Radio Group</Button> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>Panel Position</DropdownMenuLabel> <DropdownMenuRadioGroup value={position} onValueChange={setPosition}> <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem> <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem> <DropdownMenuRadioItem value="right" disabled> Right </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuContent> </DropdownMenu> );}Radio with Icons
Same as Radio Group but each item carries a leading Phosphor icon.
function RadioIconsDemo() { const [paymentMethod, setPaymentMethod] = React.useState("card"); return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Payment Method</Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-56"> <DropdownMenuLabel>Select Payment Method</DropdownMenuLabel> <DropdownMenuRadioGroup value={paymentMethod} onValueChange={setPaymentMethod}> <DropdownMenuRadioItem value="card"> <CreditCard /> Credit Card </DropdownMenuRadioItem> <DropdownMenuRadioItem value="paypal"> <Wallet /> PayPal </DropdownMenuRadioItem> <DropdownMenuRadioItem value="bank"> <Buildings /> Bank Transfer </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuContent> </DropdownMenu> );}Avatar
Account-switcher pattern: a wide trigger with Avatar + name/email + chevron, alongside an icon-only avatar trigger that shares the same menu content.
function AvatarDemo() { const menuContent = ( <> <DropdownMenuGroup> <DropdownMenuItem> <SealCheck /> Account </DropdownMenuItem> <DropdownMenuItem> <CreditCard /> Billing </DropdownMenuItem> <DropdownMenuItem> <Bell /> Notifications </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <SignOut /> Sign Out </DropdownMenuItem> </> ); return ( <div className="flex items-center justify-between gap-4"> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline" className="h-12 justify-start gap-2 px-2 md:max-w-[200px]" > <Avatar> <AvatarImage src="https://github.com/shadcn.png" alt="shadcn" /> <AvatarFallback className="rounded-lg">CN</AvatarFallback> </Avatar> <div className="grid flex-1 text-left leading-tight"> <span className="truncate text-sm font-semibold">shadcn</span> <span className="truncate text-xs text-fg-muted"> shadcn@example.com </span> </div> <CaretUpDown className="ml-auto text-fg-muted" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-(--radix-dropdown-menu-trigger-width) min-w-56"> {menuContent} </DropdownMenuContent> </DropdownMenu> <DropdownMenu> <DropdownMenuTrigger className="rounded-full outline-none focus-visible:ring-3 focus-visible:ring-border-focus/50"> <Avatar> <AvatarImage src="https://github.com/shadcn.png" alt="shadcn" /> <AvatarFallback>LR</AvatarFallback> </Avatar> </DropdownMenuTrigger> <DropdownMenuContent align="end" side="top"> {menuContent} </DropdownMenuContent> </DropdownMenu> </div> );}Complex
Combines groups, labels, icons, shortcuts, checkboxes, a submenu, and a destructive action — a kitchen-sink reference for non-trivial dropdown layouts.
<DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline">Complex Menu</Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-56"> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem> <User /> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> {/* …Billing, Settings… */} </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>View</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showSidebar} onCheckedChange={setShowSidebar}> <SidebarSimple /> Sidebar </DropdownMenuCheckboxItem> {/* …Status Bar… */} </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuSub> <DropdownMenuSubTrigger> <Users /> Invite Users </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuItem> <Envelope /> Email </DropdownMenuItem> {/* …Message, More… */} </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <SignOut /> Sign Out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent></DropdownMenu>