"use client";
import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuDemo() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent align="start"> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Billing <DropdownMenuShortcut>⌘B</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Settings <DropdownMenuShortcut>⌘S</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <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> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem>GitHub</DropdownMenuItem> <DropdownMenuItem>Support</DropdownMenuItem> <DropdownMenuItem disabled>API</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive"> Log out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}pnpm dlx shadcn@latest add @herocn/dropdown-menuimport { Button } from "@/components/ui/button"import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu"<DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuSeparator /> </DropdownMenuGroup> <DropdownMenuGroup> <DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuItem>Subscription</DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent></DropdownMenu>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 └── DropdownMenuItemA basic dropdown menu with labels and separators.
"use client";
import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuBasic() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </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> );}Use DropdownMenuSub to nest secondary actions.
"use client";
import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuSubmenu() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuItem>Email</DropdownMenuItem> <DropdownMenuItem>Message</DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> More options </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuItem>Calendly</DropdownMenuItem> <DropdownMenuItem>Slack</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem>Webhook</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> Advanced... <DropdownMenuShortcut>⌘+</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuItem> New Team <DropdownMenuShortcut>⌘+T</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Add DropdownMenuShortcut to show keyboard hints.
"use client";
import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuShortcuts() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Billing <DropdownMenuShortcut>⌘B</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> Settings <DropdownMenuShortcut>⌘S</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> Log out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Combine icons with labels for quick scanning.
"use client";
import { CreditCardIcon, LogOutIcon, SettingsIcon, UserIcon,} from "lucide-react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuIcons() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem> <UserIcon /> Profile </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> Billing </DropdownMenuItem> <DropdownMenuItem> <SettingsIcon /> Settings </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <LogOutIcon /> Log out </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> );}Use DropdownMenuCheckboxItem for toggles.
"use client";
import * as React from "react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuCheckboxes() { const [showStatusBar, setShowStatusBar] = React.useState(true); const [showActivityBar, setShowActivityBar] = React.useState(false); const [showPanel, setShowPanel] = React.useState(false);
return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Appearance</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showStatusBar ?? false} onCheckedChange={setShowStatusBar} > Status Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} disabled > Activity Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel} > Panel </DropdownMenuCheckboxItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Add icons to checkbox items.
"use client";
import { BellIcon, MailIcon, MessageSquareIcon } from "lucide-react";import * as React from "react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuCheckboxesIcons() { const [notifications, setNotifications] = React.useState({ email: true, sms: false, push: true, });
return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Notifications </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Notification Preferences</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={notifications.email} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, email: checked === true, })) } > <MailIcon /> Email notifications </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.sms} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, sms: checked === true, })) } > <MessageSquareIcon /> SMS notifications </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.push} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, push: checked === true, })) } > <BellIcon /> Push notifications </DropdownMenuCheckboxItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Use DropdownMenuRadioGroup for exclusive choices.
"use client";
import * as React from "react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuRadioGroupDemo() { const [position, setPosition] = React.useState("bottom");
return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Panel Position</DropdownMenuLabel> <DropdownMenuRadioGroup value={position} onValueChange={setPosition}> <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem> <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem> <DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Show radio options with icons.
"use client";
import { Building2Icon, CreditCardIcon, WalletIcon } from "lucide-react";import * as React from "react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuRadioIcons() { const [paymentMethod, setPaymentMethod] = React.useState("card");
return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Payment Method </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Select Payment Method</DropdownMenuLabel> <DropdownMenuRadioGroup value={paymentMethod} onValueChange={setPaymentMethod} > <DropdownMenuRadioItem value="card"> <CreditCardIcon /> Credit Card </DropdownMenuRadioItem> <DropdownMenuRadioItem value="paypal"> <WalletIcon /> PayPal </DropdownMenuRadioItem> <DropdownMenuRadioItem value="bank"> <Building2Icon /> Bank Transfer </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Use variant="destructive" for irreversible actions.
"use client";
import { PencilIcon, ShareIcon, TrashIcon } from "lucide-react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuDestructive() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Actions </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuItem> <PencilIcon /> Edit </DropdownMenuItem> <DropdownMenuItem> <ShareIcon /> Share </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive"> <TrashIcon /> Delete </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}An account switcher dropdown triggered by an avatar.
"use client";
import { BadgeCheckIcon, BellIcon, CreditCardIcon, LogOutIcon,} from "lucide-react";import { Avatar, AvatarFallback, AvatarImage,} from "@/components/ui/avatar";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuAvatar() { return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="ghost" size="icon" className="rounded-full" />} > <Avatar> <AvatarImage src="https://github.com/maqed.png" alt="Maqed" /> <AvatarFallback>Mqd</AvatarFallback> </Avatar> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuGroup> <DropdownMenuItem> <BadgeCheckIcon /> Account </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> Billing </DropdownMenuItem> <DropdownMenuItem> <BellIcon /> Notifications </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuItem> <LogOutIcon /> Sign Out </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> );}A richer example combining groups, icons, and submenus.
"use client";
import { BellIcon, CreditCardIcon, DownloadIcon, EyeIcon, FileCodeIcon, FileIcon, FileTextIcon, FolderIcon, FolderOpenIcon, FolderSearchIcon, HelpCircleIcon, KeyboardIcon, LanguagesIcon, LayoutIcon, LogOutIcon, MailIcon, MonitorIcon, MoonIcon, MoreHorizontalIcon, PaletteIcon, SaveIcon, SettingsIcon, ShieldIcon, SunIcon, UserIcon,} from "lucide-react";import * as React from "react";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuComplex() { const [notifications, setNotifications] = React.useState({ email: true, sms: false, push: true, }); const [theme, setTheme] = React.useState("light");
return ( <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Complex Menu </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>File</DropdownMenuLabel> <DropdownMenuItem> <FileIcon /> New File <DropdownMenuShortcut>⌘N</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> <FolderIcon /> New Folder <DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <FolderOpenIcon /> Open Recent </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuLabel>Recent Projects</DropdownMenuLabel> <DropdownMenuItem> <FileCodeIcon /> Project Alpha </DropdownMenuItem> <DropdownMenuItem> <FileCodeIcon /> Project Beta </DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <MoreHorizontalIcon /> More Projects </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuItem> <FileCodeIcon /> Project Gamma </DropdownMenuItem> <DropdownMenuItem> <FileCodeIcon /> Project Delta </DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <FolderSearchIcon /> Browse... </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuSeparator /> <DropdownMenuItem> <SaveIcon /> Save <DropdownMenuShortcut>⌘S</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> <DownloadIcon /> Export <DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>View</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={notifications.email} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, email: checked === true, })) } > <EyeIcon /> Show Sidebar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.sms} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, sms: checked === true, })) } > <LayoutIcon /> Show Status Bar </DropdownMenuCheckboxItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <PaletteIcon /> Theme </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuLabel>Appearance</DropdownMenuLabel> <DropdownMenuRadioGroup value={theme} onValueChange={setTheme} > <DropdownMenuRadioItem value="light"> <SunIcon /> Light </DropdownMenuRadioItem> <DropdownMenuRadioItem value="dark"> <MoonIcon /> Dark </DropdownMenuRadioItem> <DropdownMenuRadioItem value="system"> <MonitorIcon /> System </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>Account</DropdownMenuLabel> <DropdownMenuItem> <UserIcon /> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> Billing </DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <SettingsIcon /> Settings </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuLabel>Preferences</DropdownMenuLabel> <DropdownMenuItem> <KeyboardIcon /> Keyboard Shortcuts </DropdownMenuItem> <DropdownMenuItem> <LanguagesIcon /> Language </DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <BellIcon /> Notifications </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuLabel> Notification Types </DropdownMenuLabel> <DropdownMenuCheckboxItem checked={notifications.push} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, push: checked === true, })) } > <BellIcon /> Push Notifications </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={notifications.email} onCheckedChange={(checked) => setNotifications((prev) => ({ ...prev, email: checked === true, })) } > <MailIcon /> Email Notifications </DropdownMenuCheckboxItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <ShieldIcon /> Privacy & Security </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <HelpCircleIcon /> Help & Support </DropdownMenuItem> <DropdownMenuItem> <FileTextIcon /> Documentation </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive"> <LogOutIcon /> Sign Out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}Wrap the menu in DropdownMenuFilterProvider and use DropdownMenuInput with DropdownMenuList to filter items.
"use client";
import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuEmpty, DropdownMenuFilterProvider, DropdownMenuGroup, DropdownMenuInput, DropdownMenuItem, DropdownMenuLabel, DropdownMenuList, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
export function DropdownMenuFilterable() { return ( <DropdownMenuFilterProvider> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="tertiary" />}> Open </DropdownMenuTrigger> <DropdownMenuContent align="start" className="w-64 overflow-hidden"> <DropdownMenuInput aria-label="Filter actions" placeholder="e.g. Save" /> <DropdownMenuEmpty>No actions found.</DropdownMenuEmpty> <DropdownMenuList className="max-h-72"> <DropdownMenuGroup data-filter-section> <DropdownMenuLabel>File</DropdownMenuLabel> <DropdownMenuItem>New file</DropdownMenuItem> <DropdownMenuItem>Open file</DropdownMenuItem> <DropdownMenuItem>Save</DropdownMenuItem> <DropdownMenuItem>Save as</DropdownMenuItem> <DropdownMenuItem>Duplicate</DropdownMenuItem> <DropdownMenuItem>Rename</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuGroup data-filter-section> <DropdownMenuLabel>Organize</DropdownMenuLabel> <FilterableSubmenu label="Move to folder" inputLabel="Filter folders" placeholder="e.g. Projects" emptyText="No folders found." options={folderOptions} /> <DropdownMenuSub> <DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> {sharingOptions.map((option) => ( <DropdownMenuItem key={option}>{option}</DropdownMenuItem> ))} </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <FilterableSubmenu label="Export" inputLabel="Filter export formats" placeholder="e.g. PDF" emptyText="No export formats found." options={exportOptions} /> <DropdownMenuItem>Download a copy</DropdownMenuItem> <DropdownMenuItem>Delete</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuRadioGroup data-filter-section defaultValue="date"> <DropdownMenuSeparator data-filter-separator /> <DropdownMenuLabel>Sort by</DropdownMenuLabel> <DropdownMenuRadioItem value="date"> Date modified </DropdownMenuRadioItem> <DropdownMenuRadioItem value="name">Name</DropdownMenuRadioItem> <DropdownMenuRadioItem value="size">Size</DropdownMenuRadioItem> </DropdownMenuRadioGroup> <DropdownMenuGroup data-filter-section> <DropdownMenuSeparator data-filter-separator /> <DropdownMenuLabel>View</DropdownMenuLabel> <DropdownMenuCheckboxItem defaultChecked> Show details </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem>Show sidebar</DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem> Keep available offline </DropdownMenuCheckboxItem> </DropdownMenuGroup> </DropdownMenuList> </DropdownMenuContent> </DropdownMenu> </DropdownMenuFilterProvider> );}
interface FilterableSubmenuProps { label: string; inputLabel: string; placeholder: string; emptyText: string; options: readonly string[];}
function FilterableSubmenu(props: FilterableSubmenuProps) { return ( <DropdownMenuFilterProvider> <DropdownMenuSub> <DropdownMenuSubTrigger>{props.label}</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuInput aria-label={props.inputLabel} placeholder={props.placeholder} /> <DropdownMenuEmpty>{props.emptyText}</DropdownMenuEmpty> <DropdownMenuList className="max-h-72"> {props.options.map((option) => ( <DropdownMenuItem key={option}>{option}</DropdownMenuItem> ))} </DropdownMenuList> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuFilterProvider> );}
const sharingOptions = [ "Email", "Messages", "AirDrop", "Copy link", "Invite collaborators", "Publish to web", "Send a copy",];
const folderOptions = [ "Desktop", "Documents", "Downloads", "Projects", "Archive", "Shared", "Trash",];
const exportOptions = [ "PDF document", "Word document", "Plain text", "Rich text", "Markdown", "HTML page", "Image",];"use client";
import { CreditCardIcon, SettingsIcon, UserIcon } from "lucide-react";import * as React from "react";
import { type Translations, useTranslation,} from "@/components/language-selector";import { Button } from "@/components/ui/button";import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu";
const translations: Translations = { en: { dir: "ltr", values: { open: "Open", account: "Account", profile: "Profile", billing: "Billing", settings: "Settings", logout: "Log out", team: "Team", inviteUsers: "Invite users", email: "Email", message: "Message", more: "More", calendar: "Calendar", chat: "Chat", webhook: "Webhook", advanced: "Advanced...", newTeam: "New Team", view: "View", statusBar: "Status Bar", activityBar: "Activity Bar", panel: "Panel", position: "Position", top: "Top", bottom: "Bottom", right: "Right", left: "Left", }, }, ar: { dir: "rtl", values: { open: "افتح القائمة", account: "الحساب", profile: "الملف الشخصي", billing: "الفوترة", settings: "الإعدادات", logout: "تسجيل الخروج", team: "الفريق", inviteUsers: "دعوة المستخدمين", email: "البريد الإلكتروني", message: "رسالة", more: "المزيد", calendar: "تقويم", chat: "دردشة", webhook: "Webhook", advanced: "متقدم...", newTeam: "فريق جديد", view: "عرض", statusBar: "شريط الحالة", activityBar: "شريط النشاط", panel: "اللوحة", position: "الموضع", top: "أعلى", bottom: "أسفل", right: "يمين", left: "يسار", }, }, he: { dir: "rtl", values: { open: "פתח תפריט", account: "חשבון", profile: "פרופיל", billing: "חיוב", settings: "הגדרות", logout: "התנתק", team: "הצוות", inviteUsers: "הזמן משתמשים", email: "אימייל", message: "הודעה", more: "עוד", calendar: "יומן", chat: "צ'אט", webhook: "Webhook", advanced: "מתקדם...", newTeam: "צוות חדש", view: "תצוגה", statusBar: "שורת סטטוס", activityBar: "שורת פעילות", panel: "לוח", position: "מיקום", top: "למעלה", bottom: "למטה", right: "ימין", left: "שמאל", }, },};
export function DropdownMenuRtl() { const { dir, language, t } = useTranslation(translations, "ar"); const [showStatusBar, setShowStatusBar] = React.useState(true); const [showActivityBar, setShowActivityBar] = React.useState(false); const [showPanel, setShowPanel] = React.useState(false); const [position, setPosition] = React.useState("bottom");
return ( <DropdownMenu data-lang={language}> <DropdownMenuTrigger render={ <Button variant="tertiary" data-lang={language}> {t.open} </Button> } /> <DropdownMenuContent align={dir === "rtl" ? "end" : "start"} dir={dir} className="w-36" data-lang={dir === "rtl" ? language : undefined} > <DropdownMenuGroup> <DropdownMenuSub> <DropdownMenuSubTrigger>{t.account}</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent dir={dir} data-lang={dir === "rtl" ? language : undefined} > <DropdownMenuGroup> <DropdownMenuItem> <UserIcon /> {t.profile} </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> {t.billing} </DropdownMenuItem> <DropdownMenuItem> <SettingsIcon /> {t.settings} </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>{t.team}</DropdownMenuLabel> <DropdownMenuItem>{t.team}</DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger>{t.inviteUsers}</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent dir={dir} data-lang={dir === "rtl" ? language : undefined} > <DropdownMenuItem>{t.email}</DropdownMenuItem> <DropdownMenuItem>{t.message}</DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger>{t.more}</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent dir={dir} data-lang={dir === "rtl" ? language : undefined} > <DropdownMenuItem>{t.calendar}</DropdownMenuItem> <DropdownMenuItem>{t.chat}</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem>{t.webhook}</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuSeparator /> <DropdownMenuItem>{t.advanced}</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuItem> {t.newTeam} <DropdownMenuShortcut>⌘+T</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>{t.view}</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar} > {t.statusBar} </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} > {t.activityBar} </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel} > {t.panel} </DropdownMenuCheckboxItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>{t.position}</DropdownMenuLabel> <DropdownMenuRadioGroup value={position} onValueChange={setPosition}> <DropdownMenuRadioItem value="top">{t.top}</DropdownMenuRadioItem> <DropdownMenuRadioItem value="bottom"> {t.bottom} </DropdownMenuRadioItem> <DropdownMenuRadioItem value="right"> {t.right} </DropdownMenuRadioItem> <DropdownMenuRadioItem value="left">{t.left}</DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive">{t.logout}</DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> );}See the Base UI documentation for the full API reference.