Dropdown Menu
Contextual action menu with keyboard navigation, shortcuts, checkboxes, and radio groups.
Examples
#Checkbox items
#A column-toggle menu — checkbox items drive state, with a live count below.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import * as React from "react";
export function DropdownMenuCheckboxes() {
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">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-40">
<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>
);
}
Avatar
#An account switcher dropdown triggered by an avatar.
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { BadgeCheckIcon, BellIcon, CreditCardIcon, LogOutIcon } from "lucide-react";
export function DropdownMenuAvatar() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="rounded-full">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="codefast" />
<AvatarFallback>LR</AvatarFallback>
</Avatar>
</Button>
</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>
);
}
Basic
#A basic dropdown menu with labels and separators.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
export function DropdownMenuBasic() {
return (
<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>
);
}
Checkboxes Icons
#Add icons to checkbox items.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { BellIcon, MailIcon, MessageSquareIcon } from "lucide-react";
import * as React from "react";
export function DropdownMenuCheckboxesIcons() {
const [notifications, setNotifications] = React.useState({
email: true,
sms: false,
push: true,
});
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Notifications</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-48">
<DropdownMenuGroup>
<DropdownMenuLabel>Notification Preferences</DropdownMenuLabel>
<DropdownMenuCheckboxItem
checked={notifications.email}
onCheckedChange={(checked) => setNotifications({ ...notifications, email: checked === true })}
>
<MailIcon />
Email notifications
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.sms}
onCheckedChange={(checked) => setNotifications({ ...notifications, sms: checked === true })}
>
<MessageSquareIcon />
SMS notifications
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.push}
onCheckedChange={(checked) => setNotifications({ ...notifications, push: checked === true })}
>
<BellIcon />
Push notifications
</DropdownMenuCheckboxItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
Complex
#A richer example combining groups, icons, and submenus.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
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";
export function DropdownMenuComplex() {
const [notifications, setNotifications] = React.useState({
email: true,
sms: false,
push: true,
});
const [theme, setTheme] = React.useState("light");
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Complex Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-44">
<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>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
<DropdownMenuItem>
<FileCodeIcon />
Project Alpha
</DropdownMenuItem>
<DropdownMenuItem>
<FileCodeIcon />
Project Beta
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<MoreHorizontalIcon />
More Projects
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>
<FileCodeIcon />
Project Gamma
</DropdownMenuItem>
<DropdownMenuItem>
<FileCodeIcon />
Project Delta
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<FolderSearchIcon />
Browse...
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</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({ ...notifications, email: checked === true })}
>
<EyeIcon />
Show Sidebar
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.sms}
onCheckedChange={(checked) => setNotifications({ ...notifications, sms: checked === true })}
>
<LayoutIcon />
Show Status Bar
</DropdownMenuCheckboxItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<PaletteIcon />
Theme
</DropdownMenuSubTrigger>
<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>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuLabel>Account</DropdownMenuLabel>
<DropdownMenuItem>
<UserIcon />
Profile
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<CreditCardIcon />
Billing
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<SettingsIcon />
Settings
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Preferences</DropdownMenuLabel>
<DropdownMenuItem>
<KeyboardIcon />
Keyboard Shortcuts
</DropdownMenuItem>
<DropdownMenuItem>
<LanguagesIcon />
Language
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<BellIcon />
Notifications
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Notification Types</DropdownMenuLabel>
<DropdownMenuCheckboxItem
checked={notifications.push}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
push: checked === true,
})
}
>
<BellIcon />
Push Notifications
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.email}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
email: checked === true,
})
}
>
<MailIcon />
Email Notifications
</DropdownMenuCheckboxItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<ShieldIcon />
Privacy & Security
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</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>
);
}
Destructive
#Use variant='destructive' for irreversible actions.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { PencilIcon, ShareIcon, TrashIcon } from "lucide-react";
export function DropdownMenuDestructive() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuItem>
<PencilIcon />
Edit
</DropdownMenuItem>
<DropdownMenuItem>
<ShareIcon />
Share
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<TrashIcon />
Delete
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
Icons
#Combine icons with labels for quick scanning.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { CreditCardIcon, LogOutIcon, SettingsIcon, UserIcon } from "lucide-react";
export function DropdownMenuIcons() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>
<UserIcon />
Profile
</DropdownMenuItem>
<DropdownMenuItem>
<CreditCardIcon />
Billing
</DropdownMenuItem>
<DropdownMenuItem>
<SettingsIcon />
Settings
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
<LogOutIcon />
Log out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
Radio Group
#Use DropdownMenuRadioGroup for exclusive choices.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import * as React from "react";
export function DropdownMenuRadioGroupDemo() {
const [position, setPosition] = React.useState("bottom");
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-32">
<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>
);
}
Radio Icons
#Show radio options with icons.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { Building2Icon, CreditCardIcon, WalletIcon } from "lucide-react";
import * as React from "react";
export function DropdownMenuRadioIcons() {
const [paymentMethod, setPaymentMethod] = React.useState("card");
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Payment Method</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="min-w-56">
<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>
);
}
RTL
#Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { CreditCardIcon, SettingsIcon, UserIcon } from "lucide-react";
import * as React from "react";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
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: "خطاف ويب",
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>
<DropdownMenuTrigger asChild>
<Button variant="outline">{t.open}</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-36" data-lang={dir === "rtl" ? language : undefined}>
<DropdownMenuGroup>
<DropdownMenuSub>
<DropdownMenuSubTrigger>{t.account}</DropdownMenuSubTrigger>
<DropdownMenuSubContent data-lang={dir === "rtl" ? language : undefined}>
<DropdownMenuGroup>
<DropdownMenuItem>
<UserIcon />
{t.profile}
</DropdownMenuItem>
<DropdownMenuItem>
<CreditCardIcon />
{t.billing}
</DropdownMenuItem>
<DropdownMenuItem>
<SettingsIcon />
{t.settings}
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuLabel>{t.team}</DropdownMenuLabel>
<DropdownMenuItem>{t.team}</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>{t.inviteUsers}</DropdownMenuSubTrigger>
<DropdownMenuSubContent data-lang={dir === "rtl" ? language : undefined}>
<DropdownMenuItem>{t.email}</DropdownMenuItem>
<DropdownMenuItem>{t.message}</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>{t.more}</DropdownMenuSubTrigger>
<DropdownMenuSubContent data-lang={dir === "rtl" ? language : undefined}>
<DropdownMenuItem>{t.calendar}</DropdownMenuItem>
<DropdownMenuItem>{t.chat}</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>{t.webhook}</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>{t.advanced}</DropdownMenuItem>
</DropdownMenuSubContent>
</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>
);
}
Shortcuts
#Add DropdownMenuShortcut to show keyboard hints.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
export function DropdownMenuShortcuts() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</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 />
<DropdownMenuItem>
Log out
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
Submenu
#Use DropdownMenuSub to nest secondary actions.
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
export function DropdownMenuSubmenu() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>Email</DropdownMenuItem>
<DropdownMenuItem>Message</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>More options</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>Calendly</DropdownMenuItem>
<DropdownMenuItem>Slack</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Webhook</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>Advanced...</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuItem>
New Team
<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
Anatomy
#How the parts nest — every slot the component exposes, in composition order.
Features
#- variant="destructive" on DropdownMenuItem tints the text/icon and the focus background for irreversible actions.
- inset on Item/SubTrigger/Label aligns text with icon-led sibling items that don't have their own icon.
- DropdownMenuSub/SubTrigger/SubContent nest a secondary menu; DropdownMenuShortcut right-aligns a keyboard-hint string.
- DropdownMenuCheckboxItem and DropdownMenuRadioGroup/RadioItem add toggleable or exclusive-choice items inside the menu.
API reference
#Props for each part of the component. All native element props are also forwarded.
DropdownMenuCheckboxItem
A menu item with a checkmark you control.
checkedboolean | "indeterminate"The controlled checked state.
onCheckedChange(checked: boolean) => voidCalled when the checked state changes.
DropdownMenuRadioGroup
Single-choice section inside the menu.
valuestringThe controlled chosen RadioItem value.
onValueChange(value: string) => voidCalled when the chosen RadioItem value changes.
DropdownMenuRadioItem
One choice within a DropdownMenuRadioGroup.
valuestringThis item's value, matched against the group's controlled value (required).
DropdownMenuContent
side"top" | "right" | "bottom" | "left"The preferred edge of the trigger to render against.
Default
"bottom"align"start" | "center" | "end"The preferred alignment against the trigger.
Default
"center"
Accessibility
#Built to be keyboard-navigable and screen-reader friendly out of the box.
| Key | Function |
|---|---|
| Space | Opens the menu from the trigger. |
| Arrow+Down | Moves to the next item. |
| Arrow+Up | Moves to the previous item. |
| Enter | Activates the focused item. |
| Esc | Closes the menu and restores focus. |
- Implements the ARIA menu pattern with type-ahead and roving focus.
- Checkbox and radio items expose aria-checked so their state is announced.
- Use a Select (listbox) when the goal is choosing a form value, not running an action.
Guidelines
#Conventions that keep usage consistent across an app.
Do
- Group related actions and label the groups.
- Use checkbox items for toggles and a radio group for one-of-many.
Don’t
- Don’t nest more than one level of submenus.
- Don’t put primary page actions only in a dropdown.
Related
#Related components
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.