Dropdown menustandard
버튼을 눌러 여는 메뉴(dropdown menu)입니다. shadcn base-nova 의 `dropdown-menu` 를 그대로 싣습니다. 오른쪽 클릭으로 여는 메뉴는 `context-menu`, 고르는 값이 입력값이면 `select` 를 씁니다.
설치
pnpm
pnpm dlx shadcn@4.23.0 add @uikit/dropdown-menuDefault
dropdown-menu-example.tsx
"use client"
import * as React from "react"
import { Example, ExampleWrapper,} from "@/components/example"import { Avatar, AvatarFallback, AvatarImage,} from "@/components/ui/avatar"import { Button } from "@/components/ui/button"import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger,} from "@/components/ui/dialog"import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu"import { ActivityIcon, ArchiveIcon, ArrowDownIcon, ArrowRightIcon, ArrowUpIcon, BadgeCheckIcon, BellIcon, Building2Icon, ChevronsUpDownIcon, ClipboardPasteIcon, CopyIcon, CreditCardIcon, HelpCircleIcon, LayoutIcon, LogOutIcon, MailIcon, MessageSquareIcon, PanelLeftIcon, PencilIcon, PlusCircleIcon, ScissorsIcon, SettingsIcon, ShareIcon, TrashIcon, UserIcon, UsersIcon, WalletIcon } from "lucide-react"
export default function DropdownMenuExample() { return ( <ExampleWrapper> <DropdownMenuBasic /> <DropdownMenuComplex /> <DropdownMenuSides /> <DropdownMenuWithIcons /> <DropdownMenuWithShortcuts /> <DropdownMenuWithSubmenu /> <DropdownMenuWithCheckboxes /> <DropdownMenuWithCheckboxesIcons /> <DropdownMenuWithRadio /> <DropdownMenuWithRadioIcons /> <DropdownMenuWithDestructive /> <DropdownMenuWithAvatar /> <DropdownMenuInDialog /> <DropdownMenuWithInset /> </ExampleWrapper> )}
function DropdownMenuBasic() { return ( <Example title="Basic"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > 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> </Example> )}
function DropdownMenuSides() { return ( <Example title="Sides" containerClassName="col-span-2"> <div className="flex flex-wrap justify-center gap-2"> {( [ "inline-start", "left", "top", "bottom", "right", "inline-end", ] as const ).map((side) => ( <DropdownMenu key={side}> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit capitalize" />} > {side.replace("-", " ")} </DropdownMenuTrigger> <DropdownMenuContent side={side}> <DropdownMenuGroup> <DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Settings</DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> ))} </div> </Example> )}
function DropdownMenuWithIcons() { return ( <Example title="With Icons"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > 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> </Example> )}
function DropdownMenuWithShortcuts() { return ( <Example title="With Shortcuts"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > 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> <DropdownMenuItem> Keyboard shortcuts <DropdownMenuShortcut>⌘K</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuItem> Log out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuWithSubmenu() { return ( <Example title="With Submenu"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Open </DropdownMenuTrigger> <DropdownMenuContent> <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> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuWithCheckboxes() { const [showStatusBar, setShowStatusBar] = React.useState(true) const [showActivityBar, setShowActivityBar] = React.useState(false) const [showPanel, setShowPanel] = React.useState(false)
return ( <Example title="With Checkboxes"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Checkboxes </DropdownMenuTrigger> <DropdownMenuContent className="min-w-40"> <DropdownMenuGroup> <DropdownMenuLabel>Appearance</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar} > <LayoutIcon /> Status Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} disabled > <ActivityIcon /> Activity Bar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel} > <PanelLeftIcon /> Panel </DropdownMenuCheckboxItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuWithRadio() { const [position, setPosition] = React.useState("bottom")
return ( <Example title="With Radio Group"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Radio Group </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Panel Position</DropdownMenuLabel> <DropdownMenuRadioGroup value={position} onValueChange={setPosition} > <DropdownMenuRadioItem value="top"> <ArrowUpIcon /> Top </DropdownMenuRadioItem> <DropdownMenuRadioItem value="bottom"> <ArrowDownIcon /> Bottom </DropdownMenuRadioItem> <DropdownMenuRadioItem value="right" disabled> <ArrowRightIcon /> Right </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuWithCheckboxesIcons() { const [notifications, setNotifications] = React.useState({ email: true, sms: false, push: true, })
return ( <Example title="Checkboxes with Icons"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Notifications </DropdownMenuTrigger> <DropdownMenuContent className="min-w-56"> <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> </Example> )}
function DropdownMenuWithRadioIcons() { const [paymentMethod, setPaymentMethod] = React.useState("card")
return ( <Example title="Radio with Icons"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Payment Method </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> </Example> )}
function DropdownMenuWithDestructive() { return ( <Example title="With Destructive Items"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Actions </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem> <PencilIcon /> Edit </DropdownMenuItem> <DropdownMenuItem> <ShareIcon /> Share </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem> <ArchiveIcon /> Archive </DropdownMenuItem> <DropdownMenuItem variant="destructive"> <TrashIcon /> Delete </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuWithAvatar() { const menuContent = ( <> <DropdownMenuGroup> <DropdownMenuItem> <BadgeCheckIcon /> Account </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> Billing </DropdownMenuItem> <DropdownMenuItem> <BellIcon /> Notifications </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuItem> <LogOutIcon /> Sign Out </DropdownMenuItem> </> )
return ( <Example title="With Avatar"> <div className="flex items-center justify-between gap-4"> <DropdownMenu> <DropdownMenuTrigger render={ <Button variant="outline" className="h-12 justify-start px-2 md:max-w-[200px] style-sera:font-normal style-sera:tracking-normal style-sera:normal-case" /> } > <Avatar> <AvatarImage src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%208%208'%3E%3Crect%20width='8'%20height='8'%20fill='%2364748b'/%3E%3C/svg%3E" alt="Shadcn" /> <AvatarFallback className="rounded-lg">CN</AvatarFallback> </Avatar> <div className="grid flex-1 text-left text-sm leading-tight"> <span className="truncate font-semibold">shadcn</span> <span className="truncate text-xs text-muted-foreground"> shadcn@example.com </span> </div> <ChevronsUpDownIcon className="ml-auto text-muted-foreground" /> </DropdownMenuTrigger> <DropdownMenuContent className="w-(--anchor-width) min-w-56"> {menuContent} </DropdownMenuContent> </DropdownMenu> <DropdownMenu> <DropdownMenuTrigger render={ <Button variant="ghost" size="icon" className="rounded-full" /> } > <Avatar> <AvatarImage src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%208%208'%3E%3Crect%20width='8'%20height='8'%20fill='%2364748b'/%3E%3C/svg%3E" alt="shadcn" /> <AvatarFallback>LR</AvatarFallback> </Avatar> </DropdownMenuTrigger> <DropdownMenuContent align="end" side="top"> {menuContent} </DropdownMenuContent> </DropdownMenu> </div> </Example> )}
function DropdownMenuInDialog() { return ( <Example title="In Dialog"> <Dialog> <DialogTrigger render={<Button variant="outline" />}> Open Dialog </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Dropdown Menu Example</DialogTitle> <DialogDescription> Click the button below to see the dropdown menu. </DialogDescription> </DialogHeader> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Open Menu </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuItem> <CopyIcon /> Copy </DropdownMenuItem> <DropdownMenuItem> <ScissorsIcon /> Cut </DropdownMenuItem> <DropdownMenuItem> <ClipboardPasteIcon /> Paste </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuSub> <DropdownMenuSubTrigger>More Options</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuItem>Save Page...</DropdownMenuItem> <DropdownMenuItem>Create Shortcut...</DropdownMenuItem> <DropdownMenuItem>Name Window...</DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem>Developer Tools</DropdownMenuItem> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> <DropdownMenuSeparator /> <DropdownMenuItem variant="destructive"> <TrashIcon /> Delete </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </DialogContent> </Dialog> </Example> )}
function DropdownMenuWithInset() { const [showBookmarks, setShowBookmarks] = React.useState(true) const [showUrls, setShowUrls] = React.useState(false) const [theme, setTheme] = React.useState("system")
return ( <Example title="With Inset"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Open </DropdownMenuTrigger> <DropdownMenuContent className="w-44"> <DropdownMenuGroup> <DropdownMenuLabel>Actions</DropdownMenuLabel> <DropdownMenuItem> <CopyIcon /> Copy </DropdownMenuItem> <DropdownMenuItem> <ScissorsIcon /> Cut </DropdownMenuItem> <DropdownMenuItem inset>Paste</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel inset>Appearance</DropdownMenuLabel> <DropdownMenuCheckboxItem inset checked={showBookmarks} onCheckedChange={setShowBookmarks} > Bookmarks </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem inset checked={showUrls} onCheckedChange={setShowUrls} > Full URLs </DropdownMenuCheckboxItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel inset>Theme</DropdownMenuLabel> <DropdownMenuRadioGroup value={theme} onValueChange={setTheme}> <DropdownMenuRadioItem inset value="light"> Light </DropdownMenuRadioItem> <DropdownMenuRadioItem inset value="dark"> Dark </DropdownMenuRadioItem> <DropdownMenuRadioItem inset value="system"> System </DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuSub> <DropdownMenuSubTrigger inset>More Options</DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuItem>Save Page...</DropdownMenuItem> <DropdownMenuItem>Create Shortcut...</DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuContent> </DropdownMenu> </Example> )}
function DropdownMenuComplex() { const [showSidebar, setShowSidebar] = React.useState(true) const [showStatusBar, setShowStatusBar] = React.useState(false)
return ( <Example title="Complex"> <DropdownMenu> <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />} > Complex Menu </DropdownMenuTrigger> <DropdownMenuContent className="w-56"> <DropdownMenuGroup> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem> <UserIcon /> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> <CreditCardIcon /> Billing <DropdownMenuShortcut>⌘B</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuItem> <SettingsIcon /> Settings <DropdownMenuShortcut>⌘S</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuLabel>View</DropdownMenuLabel> <DropdownMenuCheckboxItem checked={showSidebar} onCheckedChange={setShowSidebar} > <PanelLeftIcon /> Sidebar </DropdownMenuCheckboxItem> <DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar} > <LayoutIcon /> Status Bar </DropdownMenuCheckboxItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuSub> <DropdownMenuSubTrigger> <UsersIcon /> Invite Users </DropdownMenuSubTrigger> <DropdownMenuPortal> <DropdownMenuSubContent> <DropdownMenuGroup> <DropdownMenuItem> <MailIcon /> Email </DropdownMenuItem> <DropdownMenuItem> <MessageSquareIcon /> Message </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <PlusCircleIcon /> More... </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuSubContent> </DropdownMenuPortal> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <HelpCircleIcon /> Support </DropdownMenuItem> <DropdownMenuItem variant="destructive"> <LogOutIcon /> Sign Out <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </Example> )}