Dropdown menu wrappers
import { Button } from '@/components/ui/button'
import {
...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 default function DropdownMenuDemoExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-40" 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>
Log out
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Installation
npx @fictjs/shadcn@latest add dropdown-menuInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/dropdown-menu.tsx
src/components/ui/dropdown-menu.tsx
import { DropdownMenu as DropdownMenuPrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
export const DropdownMenu = DropdownMenuPrimitive.Root
export const DropdownMenuRadio = DropdownMenuPrimitive.RadioGroup
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
export const DropdownMenuGroup = DropdownMenuPrimitive.Group
export const DropdownMenuPortal = DropdownMenuPrimitive.Portal
export const DropdownMenuSub = DropdownMenuPrimitive.Sub
type GenericProps = {
class?: string
inset?: boolean
children?: unknown
[key: string]: unknown
}
export function DropdownMenuTrigger(props: GenericProps) {
return <DropdownMenuPrimitive.Trigger {...props} />
}
export function DropdownMenuContent(props: GenericProps) {
const { class: className, ...rest } = props
return (
<DropdownMenuPrimitive.Content
class={cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md', className)}
{...rest}
/>
)
}
export function DropdownMenuItem(props: GenericProps) {
const { class: className, inset, ...rest } = props
return (
<DropdownMenuPrimitive.Item
class={cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground', inset && 'pl-8', className)}
{...rest}
/>
)
}
export function DropdownMenuCheckboxItem(props: GenericProps) {
const { class: className, children, ...rest } = props
return (
<DropdownMenuPrimitive.CheckboxItem
class={cn('relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground', className)}
{...rest}
>
{children}
</DropdownMenuPrimitive.CheckboxItem>
)
}
export function DropdownMenuRadioItem(props: GenericProps) {
const { class: className, children, ...rest } = props
return (
<DropdownMenuPrimitive.RadioItem
class={cn('relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground', className)}
{...rest}
>
{children}
</DropdownMenuPrimitive.RadioItem>
)
}
export function DropdownMenuLabel(props: GenericProps) {
const { class: className, inset, ...rest } = props
return <DropdownMenuPrimitive.Label class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)} {...rest} />
}
export function DropdownMenuSeparator(props: GenericProps) {
const { class: className, ...rest } = props
return <DropdownMenuPrimitive.Separator class={cn('-mx-1 my-1 h-px bg-muted', className)} {...rest} />
}
export function DropdownMenuShortcut(props: JSX.IntrinsicElements['span']) {
const { class: className, ...rest } = props
return <span class={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)} {...rest} />
}
export function DropdownMenuSubTrigger(props: GenericProps) {
const { class: className, inset, ...rest } = props
return (
<DropdownMenuPrimitive.SubTrigger
class={cn('flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent data-[state=open]:bg-accent', inset && 'pl-8', className)}
{...rest}
/>
)
}
export function DropdownMenuSubContent(props: GenericProps) {
const { class: className, ...rest } = props
return (
<DropdownMenuPrimitive.SubContent
class={cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg', className)}
{...rest}
/>
)
}
Usage
Examples
Basic
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuBasicExample() {
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>
)
}
Submenu
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuSubmenuExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<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>
<DropdownMenuSeparator />
<DropdownMenuItem>Advanced...</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuItem>
New Team
<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Shortcuts
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuShortcutsExample() {
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>
)
}
Icons
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuIconsExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Profile
</DropdownMenuItem>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Billing
</DropdownMenuItem>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Settings
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
<span aria-hidden="true">•</span>
Log out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Checkboxes
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuCheckboxesExample() {
let statusBar = $state(true)
let activityBar = $state(false)
let panel = $state(false)
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem
checked={() => statusBar}
onCheckedChange={value => {
statusBar = value
}}
>
Status Bar
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem checked={() => activityBar} disabled>
Activity Bar
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={() => panel}
onCheckedChange={value => {
panel = value
}}
>
Panel
</DropdownMenuCheckboxItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Checkboxes Icons
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
...import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
function NotificationIcon(props: { kind: 'mail' | 'message' | 'bell' }) {
return <span aria-hidden="true">{props.kind === 'mail' ? '✉' : props.kind === 'message' ? '▣' : '♢'}</span>
}
export default function DropdownMenuCheckboxesIconsExample() {
let notifications = $state({ email: true, sms: false, push: true })
return (
<DropdownMenu>
<DropdownMenuTrigger asChild><Button variant="outline">Notifications</Button></DropdownMenuTrigger>
<DropdownMenuContent class="w-48">
<DropdownMenuGroup>
<DropdownMenuLabel>Notification Preferences</DropdownMenuLabel>
<DropdownMenuCheckboxItem checked={() => notifications.email} onCheckedChange={email => { notifications = { ...notifications, email } }}><NotificationIcon kind="mail" />Email notifications</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem checked={() => notifications.sms} onCheckedChange={sms => { notifications = { ...notifications, sms } }}><NotificationIcon kind="message" />SMS notifications</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem checked={() => notifications.push} onCheckedChange={push => { notifications = { ...notifications, push } }}><NotificationIcon kind="bell" />Push notifications</DropdownMenuCheckboxItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Radio Group
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuRadioGroupExample() {
let position = $state('bottom')
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Panel Position</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup
value={() => position}
onValueChange={value => {
position = value
}}
>
<DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Radio Icons
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
...import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
function PaymentIcon(props: { kind: 'card' | 'wallet' | 'bank' }) {
return <span aria-hidden="true">{props.kind === 'card' ? '▤' : props.kind === 'wallet' ? '▱' : '▥'}</span>
}
export default function DropdownMenuRadioIconsExample() {
let paymentMethod = $state('card')
return (
<DropdownMenu>
<DropdownMenuTrigger asChild><Button variant="outline">Payment Method</Button></DropdownMenuTrigger>
<DropdownMenuContent class="min-w-56">
<DropdownMenuGroup>
<DropdownMenuLabel>Select Payment Method</DropdownMenuLabel>
<DropdownMenuRadioGroup value={() => paymentMethod} onValueChange={value => { paymentMethod = value }}>
<DropdownMenuRadioItem value="card"><PaymentIcon kind="card" />Credit Card</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="paypal"><PaymentIcon kind="wallet" />PayPal</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="bank"><PaymentIcon kind="bank" />Bank Transfer</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Destructive
import { Button } from '@/components/ui/button'
import {
...import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function DropdownMenuDestructiveExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Edit
</DropdownMenuItem>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Share
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<span aria-hidden="true">•</span>
Delete
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
Avatar
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
...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 default function DropdownMenuAvatarExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" class="rounded-full">
<Avatar>
<AvatarImage src="/avatars/shadcn.jpg" alt="shadcn" />
<AvatarFallback>LR</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Account
</DropdownMenuItem>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Billing
</DropdownMenuItem>
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Notifications
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>
<span aria-hidden="true">•</span>
Sign Out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Complex
import { Button } from '@/components/ui/button'
import {
...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'
function MenuIcon() { return <span aria-hidden="true">◇</span> }
export default function DropdownMenuComplexExample() {
let view = $state({ sidebar: true, status: false })
let theme = $state('light')
return (
<DropdownMenu>
<DropdownMenuTrigger asChild><Button variant="outline">Complex Menu</Button></DropdownMenuTrigger>
<DropdownMenuContent class="max-h-72 w-44 overflow-y-auto">
<DropdownMenuGroup><DropdownMenuLabel>File</DropdownMenuLabel>
<DropdownMenuItem><MenuIcon />New File<DropdownMenuShortcut>⌘N</DropdownMenuShortcut></DropdownMenuItem>
<DropdownMenuItem><MenuIcon />New Folder<DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut></DropdownMenuItem>
<DropdownMenuSub><DropdownMenuSubTrigger><MenuIcon />Open Recent</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent><DropdownMenuGroup><DropdownMenuLabel>Recent Projects</DropdownMenuLabel><DropdownMenuItem><MenuIcon />Project Alpha</DropdownMenuItem><DropdownMenuItem><MenuIcon />Project Beta</DropdownMenuItem><DropdownMenuSub><DropdownMenuSubTrigger>More Projects</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent><DropdownMenuItem>Project Gamma</DropdownMenuItem><DropdownMenuItem>Project Delta</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub></DropdownMenuGroup><DropdownMenuSeparator /><DropdownMenuItem><MenuIcon />Browse...</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub>
<DropdownMenuSeparator /><DropdownMenuItem><MenuIcon />Save<DropdownMenuShortcut>⌘S</DropdownMenuShortcut></DropdownMenuItem><DropdownMenuItem><MenuIcon />Export<DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut></DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup><DropdownMenuLabel>View</DropdownMenuLabel><DropdownMenuCheckboxItem checked={() => view.sidebar} onCheckedChange={sidebar => { view = { ...view, sidebar } }}><MenuIcon />Show Sidebar</DropdownMenuCheckboxItem><DropdownMenuCheckboxItem checked={() => view.status} onCheckedChange={status => { view = { ...view, status } }}><MenuIcon />Show Status Bar</DropdownMenuCheckboxItem><DropdownMenuSub><DropdownMenuSubTrigger><MenuIcon />Theme</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent><DropdownMenuLabel>Appearance</DropdownMenuLabel><DropdownMenuRadioGroup value={() => theme} onValueChange={value => { theme = value }}>{['Light', 'Dark', 'System'].map(label => <DropdownMenuRadioItem value={label.toLowerCase()}>{label}</DropdownMenuRadioItem>)}</DropdownMenuRadioGroup></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub></DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup><DropdownMenuLabel>Account</DropdownMenuLabel><DropdownMenuItem><MenuIcon />Profile<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut></DropdownMenuItem><DropdownMenuItem><MenuIcon />Billing</DropdownMenuItem><DropdownMenuSub><DropdownMenuSubTrigger><MenuIcon />Settings</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent><DropdownMenuLabel>Preferences</DropdownMenuLabel><DropdownMenuItem>Keyboard Shortcuts</DropdownMenuItem><DropdownMenuItem>Language</DropdownMenuItem><DropdownMenuSub><DropdownMenuSubTrigger>Notifications</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent><DropdownMenuLabel>Notification Types</DropdownMenuLabel><DropdownMenuCheckboxItem checked>Push Notifications</DropdownMenuCheckboxItem><DropdownMenuCheckboxItem checked>Email Notifications</DropdownMenuCheckboxItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub><DropdownMenuSeparator /><DropdownMenuItem>Privacy & Security</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub></DropdownMenuGroup>
<DropdownMenuSeparator /><DropdownMenuItem>Help & Support</DropdownMenuItem><DropdownMenuItem>Documentation</DropdownMenuItem><DropdownMenuSeparator /><DropdownMenuItem variant="destructive"><MenuIcon />Sign Out<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut></DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Rtl
import { Button } from '@/components/ui/button'
import {
...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 = {
ar: { dir: 'rtl', open: 'افتح القائمة', account: 'الحساب', profile: 'الملف الشخصي', billing: 'الفوترة', settings: 'الإعدادات', logout: 'تسجيل الخروج', team: 'الفريق', invite: 'دعوة المستخدمين', email: 'البريد الإلكتروني', message: 'رسالة', more: 'المزيد', calendar: 'تقويم', chat: 'دردشة', webhook: 'خطاف ويب', advanced: 'متقدم...', newTeam: 'فريق جديد', view: 'عرض', status: 'شريط الحالة', activity: 'شريط النشاط', panel: 'اللوحة', position: 'الموضع', top: 'أعلى', bottom: 'أسفل', right: 'يمين', left: 'يسار' },
he: { dir: 'rtl', open: 'פתח תפריט', account: 'חשבון', profile: 'פרופיל', billing: 'חיוב', settings: 'הגדרות', logout: 'התנתק', team: 'הצוות', invite: 'הזמן משתמשים', email: 'אימייל', message: 'הודעה', more: 'עוד', calendar: 'יומן', chat: "צ'אט", webhook: 'Webhook', advanced: 'מתקדם...', newTeam: 'צוות חדש', view: 'תצוגה', status: 'שורת סטטוס', activity: 'שורת פעילות', panel: 'לוח', position: 'מיקום', top: 'למעלה', bottom: 'למטה', right: 'ימין', left: 'שמאל' },
en: { dir: 'ltr', open: 'Open', account: 'Account', profile: 'Profile', billing: 'Billing', settings: 'Settings', logout: 'Log out', team: 'Team', invite: 'Invite users', email: 'Email', message: 'Message', more: 'More', calendar: 'Calendar', chat: 'Chat', webhook: 'Webhook', advanced: 'Advanced...', newTeam: 'New Team', view: 'View', status: 'Status Bar', activity: 'Activity Bar', panel: 'Panel', position: 'Position', top: 'Top', bottom: 'Bottom', right: 'Right', left: 'Left' },
} as const
export default function DropdownMenuRtlExample() {
let language = $state<keyof typeof translations>('ar')
let visibility = $state({ status: true, activity: false, panel: false })
let position = $state('bottom')
const text = () => translations[language]
return (
<div class="grid gap-4">
<select value={language} onChange={event => { language = event.currentTarget.value as keyof typeof translations }}><option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option></select>
<DropdownMenu dir={text().dir}><DropdownMenuTrigger asChild><Button variant="outline">{text().open}</Button></DropdownMenuTrigger><DropdownMenuContent class="w-36" dir={text().dir}>
<DropdownMenuGroup><DropdownMenuSub><DropdownMenuSubTrigger>{text().account}</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent dir={text().dir}><DropdownMenuItem>{text().profile}</DropdownMenuItem><DropdownMenuItem>{text().billing}</DropdownMenuItem><DropdownMenuItem>{text().settings}</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub></DropdownMenuGroup>
<DropdownMenuSeparator /><DropdownMenuGroup><DropdownMenuLabel>{text().team}</DropdownMenuLabel><DropdownMenuItem>{text().team}</DropdownMenuItem><DropdownMenuSub><DropdownMenuSubTrigger>{text().invite}</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent dir={text().dir}><DropdownMenuItem>{text().email}</DropdownMenuItem><DropdownMenuItem>{text().message}</DropdownMenuItem><DropdownMenuSub><DropdownMenuSubTrigger>{text().more}</DropdownMenuSubTrigger><DropdownMenuPortal><DropdownMenuSubContent dir={text().dir}><DropdownMenuItem>{text().calendar}</DropdownMenuItem><DropdownMenuItem>{text().chat}</DropdownMenuItem><DropdownMenuSeparator /><DropdownMenuItem>{text().webhook}</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub><DropdownMenuSeparator /><DropdownMenuItem>{text().advanced}</DropdownMenuItem></DropdownMenuSubContent></DropdownMenuPortal></DropdownMenuSub><DropdownMenuItem>{text().newTeam}<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut></DropdownMenuItem></DropdownMenuGroup>
<DropdownMenuSeparator /><DropdownMenuGroup><DropdownMenuLabel>{text().view}</DropdownMenuLabel>{(['status', 'activity', 'panel'] as const).map(key => <DropdownMenuCheckboxItem checked={() => visibility[key]} onCheckedChange={value => { visibility = { ...visibility, [key]: value } }}>{text()[key]}</DropdownMenuCheckboxItem>)}</DropdownMenuGroup>
<DropdownMenuSeparator /><DropdownMenuGroup><DropdownMenuLabel>{text().position}</DropdownMenuLabel><DropdownMenuRadioGroup value={() => position} onValueChange={value => { position = value }}>{(['top', 'bottom', 'right', 'left'] as const).map(value => <DropdownMenuRadioItem value={value}>{text()[value]}</DropdownMenuRadioItem>)}</DropdownMenuRadioGroup></DropdownMenuGroup>
<DropdownMenuSeparator /><DropdownMenuItem variant="destructive">{text().logout}</DropdownMenuItem>
</DropdownMenuContent></DropdownMenu>
</div>
)
}