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
                └── DropdownMenuItem

Examples

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>

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>

On this page