Skip to main content
PolyUI/docs

浮层组件

Dropdown Menu 下拉菜单

点击触发器后展开的下拉菜单,支持普通菜单项、分组、标签、复选框、单选组、子菜单和快捷键。

安装

bash
npx polyui add dropdown-menu

基础

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuPortal } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuBasic() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Basic</Button>} />
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>My Account</DropdownMenuLabel>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuItem>Profile</DropdownMenuItem>
          <DropdownMenuItem>Billing</DropdownMenuItem>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuSub>
            <DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
            <DropdownMenuPortal>
              <DropdownMenuSubContent>
                <DropdownMenuItem>Email</DropdownMenuItem>
                <DropdownMenuItem>Message</DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem>More...</DropdownMenuItem>
              </DropdownMenuSubContent>
            </DropdownMenuPortal>
          </DropdownMenuSub>
          <DropdownMenuItem>GitHub</DropdownMenuItem>
          <DropdownMenuItem>Support</DropdownMenuItem>
          <DropdownMenuItem disabled>API</DropdownMenuItem>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

用户切换

tsx
import { useState } from "react"
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
import { CheckIcon } from "lucide-react"
export function DropdownMenuUserSwitcher() {
  const [selectedUser, setSelectedUser] = useState(switchUsers[0])
  return (
    <DropdownMenu>
      <DropdownMenuTrigger className="bg-secondary flex items-center gap-2 rounded-lg px-3 py-2.5">
        <Avatar>
          <AvatarImage src={selectedUser.src} alt={selectedUser.name} />
          <AvatarFallback className="text-xs">{selectedUser.fallback}</AvatarFallback>
        </Avatar>
        <div className="flex flex-col gap-1 text-start leading-none">
          <span className="max-w-[17ch] truncate text-sm font-semibold leading-none">{selectedUser.name}</span>
          <span className="text-muted-foreground max-w-[20ch] truncate text-xs">{selectedUser.mail}</span>
        </div>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="start" className="w-66">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Task Assignment</DropdownMenuLabel>
          {switchUsers.map((user) => (
            <DropdownMenuItem key={user.id} onClick={() => setSelectedUser(user)}>
              <div className="flex items-center gap-2">
                <Avatar>
                  <AvatarImage src={user.src} alt={user.name} />
                  <AvatarFallback className="text-xs">{user.fallback}</AvatarFallback>
                </Avatar>
                <div className="flex flex-col gap-1 text-start leading-none">
                  <span className="max-w-[17ch] truncate text-sm font-semibold leading-none">{user.name}</span>
                  <span className="text-muted-foreground max-w-[20ch] truncate text-xs">{user.mail}</span>
                </div>
              </div>
              {selectedUser.id === user.id && <CheckIcon className="ml-auto" />}
            </DropdownMenuItem>
          ))}
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

聊天列表

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
import { Badge } from "@polyui/react/badge"
export function DropdownMenuChatList() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Chat List</Button>} />
      <DropdownMenuContent className="w-91">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Chat List</DropdownMenuLabel>
          <DropdownMenuGroup>
            {chatItems.map((item, index) => (
              <DropdownMenuItem key={index} className="justify-between">
                <Avatar>
                  <AvatarImage src={item.src} alt={item.name} />
                  <AvatarFallback className="text-xs">{item.fallback}</AvatarFallback>
                </Avatar>
                <div className="flex flex-1 flex-col">
                  <span className="text-popover-foreground">{item.name}</span>
                  <span className="text-muted-foreground text-xs">{item.message}</span>
                </div>
                {item.newMessages ? (
                  <div className="flex flex-col items-end gap-1">
                    <span className="text-muted-foreground text-xs">{item.time}</span>
                    <Badge className="h-5 min-w-5 bg-green-600 px-1 dark:bg-green-400">{item.newMessages}</Badge>
                  </div>
                ) : (
                  <span className="text-muted-foreground text-xs">{item.time}</span>
                )}
              </DropdownMenuItem>
            ))}
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

联系人列表

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
export function DropdownMenuContactList() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Contact List</Button>} />
      <DropdownMenuContent className="w-91">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Contact List</DropdownMenuLabel>
          <DropdownMenuGroup>
            {contactItems.map((item, index) => (
              <DropdownMenuItem key={index} className="justify-between">
                <Avatar>
                  <AvatarImage src={item.src} alt={item.name} />
                  <AvatarFallback className="text-xs">{item.fallback}</AvatarFallback>
                </Avatar>
                <div className="flex flex-1 flex-col">
                  <span className="text-popover-foreground">{item.name}</span>
                  <span className="text-muted-foreground text-xs">{item.mail}</span>
                </div>
                <Button variant="secondary" className="h-7 cursor-pointer rounded-md px-2">
                  Send
                </Button>
              </DropdownMenuItem>
            ))}
            <DropdownMenuItem>
              <Button className="grow">Add Contact</Button>
            </DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

会议日程

tsx
import { useState } from "react"
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
import { Switch } from "@polyui/react/switch"
export function DropdownMenuMeetingSchedule() {
  const [firstMeeting, setFirstMeeting] = useState(false)
  const [secondMeeting, setSecondMeeting] = useState(true)
  const [thirdMeeting, setThirdMeeting] = useState(false)
  const [forthMeeting, setForthMeeting] = useState(true)
  const [fifthMeeting, setFifthMeeting] = useState(false)

  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Meetings Schedule</Button>} />
      <DropdownMenuContent className="sm:w-124">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Today's meetings</DropdownMenuLabel>
          <DropdownMenuGroup>
            <DropdownMenuItem className="justify-between gap-3.5" onSelect={(event) => event.preventDefault()}>
              <span className="text-popover-foreground font-medium">08:30</span>
              <div className="flex flex-1 flex-col">
                <span className="text-popover-foreground">Daily Project Review</span>
                <span className="text-muted-foreground text-xs">Team organization</span>
              </div>
              <Avatar className="max-sm:hidden">
                <AvatarImage src="https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-11.png" alt="Hallie Richards" />
                <AvatarFallback className="text-xs">Angel</AvatarFallback>
              </Avatar>
              <div className="flex items-center gap-2">
                <span className="text-popover-foreground text-sm">Privacy</span>
                <Switch checked={firstMeeting} onCheckedChange={setFirstMeeting} />
              </div>
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between gap-3.5" onSelect={(event) => event.preventDefault()}>
              <span className="text-popover-foreground font-medium">09:00</span>
              <div className="flex flex-1 flex-col">
                <span className="text-popover-foreground">Sprint Surge</span>
                <span className="text-muted-foreground text-xs">Daily Boost for Agile Progress</span>
              </div>
              <div className="flex -space-x-3 max-sm:hidden">
                {meetingAvatars.map((avatar, index) => (
                  <Avatar key={index} className="ring-background ring-2">
                    <AvatarImage src={avatar.src} alt={avatar.name} />
                    <AvatarFallback className="text-xs">{avatar.fallback}</AvatarFallback>
                  </Avatar>
                ))}
              </div>
              <div className="flex items-center gap-2">
                <span className="text-popover-foreground text-sm">Privacy</span>
                <Switch checked={secondMeeting} onCheckedChange={setSecondMeeting} />
              </div>
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between gap-3.5" onSelect={(event) => event.preventDefault()}>
              <span className="text-popover-foreground font-medium">11:45</span>
              <div className="flex flex-1 flex-col">
                <span className="text-popover-foreground">Project Status Update</span>
                <span className="text-muted-foreground text-xs">Progress Overview Update</span>
              </div>
              <Avatar className="max-sm:hidden">
                <AvatarImage src="https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-12.png" alt="Hallie Richards" />
                <AvatarFallback className="text-xs">Angel</AvatarFallback>
              </Avatar>
              <div className="flex items-center gap-2">
                <span className="text-popover-foreground text-sm">Privacy</span>
                <Switch checked={thirdMeeting} onCheckedChange={setThirdMeeting} />
              </div>
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between gap-3.5" onSelect={(event) => event.preventDefault()}>
              <span className="text-popover-foreground font-medium">06:30</span>
              <div className="flex flex-1 flex-col">
                <span className="text-popover-foreground">Team Performance</span>
                <span className="text-muted-foreground text-xs">Team Metrics Evaluation</span>
              </div>
              <div className="flex -space-x-3 max-sm:hidden">
                {meetingAvatars.map((avatar, index) => (
                  <Avatar key={index} className="ring-background ring-2">
                    <AvatarImage src={avatar.src} alt={avatar.name} />
                    <AvatarFallback className="text-xs">{avatar.fallback}</AvatarFallback>
                  </Avatar>
                ))}
              </div>
              <div className="flex items-center gap-2">
                <span className="text-popover-foreground text-sm">Privacy</span>
                <Switch checked={forthMeeting} onCheckedChange={setForthMeeting} />
              </div>
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between gap-3.5" onSelect={(event) => event.preventDefault()}>
              <span className="text-popover-foreground font-medium">10:50</span>
              <div className="flex flex-1 flex-col">
                <span className="text-popover-foreground">Stakeholder Feedback</span>
                <span className="text-muted-foreground text-xs">Feedback from Stakeholders</span>
              </div>
              <Avatar className="max-sm:hidden">
                <AvatarImage src="https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-14.png" alt="Hallie Richards" />
                <AvatarFallback className="text-xs">Angel</AvatarFallback>
              </Avatar>
              <div className="flex items-center gap-2">
                <span className="text-popover-foreground text-sm">Privacy</span>
                <Switch checked={fifthMeeting} onCheckedChange={setFifthMeeting} />
              </div>
            </DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

编辑菜单

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { PencilIcon } from "lucide-react"
export function DropdownMenuEditMenu() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="ghost" size="icon" className="rounded-full" />}>
        <PencilIcon />
        <span className="sr-only">Edit menu</span>
      </DropdownMenuTrigger>
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Edit text</DropdownMenuLabel>
          <DropdownMenuGroup>
            {editItemDefs.map((item, index) => (
              <DropdownMenuItem key={index}>
                <span className="flex items-center justify-center rounded-md border p-2">
                  <item.icon className="size-4" />
                </span>
                <div className="flex flex-col">
                  <span className="text-popover-foreground">{item.property}</span>
                  <span className="text-muted-foreground text-xs">{item.description}</span>
                </div>
              </DropdownMenuItem>
            ))}
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

用户菜单

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuUserMenu() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="secondary" size="icon" className="overflow-hidden rounded-full" />}>
        <img src="https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png" alt="Hallie Richards" />
      </DropdownMenuTrigger>
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>My Account</DropdownMenuLabel>
          <DropdownMenuGroup>
            {accountItemDefs.map((item, index) => (
              <DropdownMenuItem key={index}>
                <item.icon />
                <span className="text-popover-foreground">{item.label}</span>
              </DropdownMenuItem>
            ))}
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

用户资料

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuPortal } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
export function DropdownMenuUserProfile() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">User Profile</Button>} />
      <DropdownMenuContent className="w-56">
        <DropdownMenuLabel className="flex items-center gap-2">
          <Avatar>
            <AvatarImage src="https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-1.png" alt="Phillip George" />
            <AvatarFallback className="text-xs">PG</AvatarFallback>
          </Avatar>
          <div className="flex flex-1 flex-col">
            <span className="text-popover-foreground">Phillip George</span>
            <span className="text-muted-foreground text-xs font-normal">phillip@example.com</span>
          </div>
        </DropdownMenuLabel>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuItem>Profile</DropdownMenuItem>
          <DropdownMenuItem>Billing</DropdownMenuItem>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuSub>
            <DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
            <DropdownMenuPortal>
              <DropdownMenuSubContent>
                <DropdownMenuItem>Email</DropdownMenuItem>
                <DropdownMenuItem>Message</DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem>More...</DropdownMenuItem>
              </DropdownMenuSubContent>
            </DropdownMenuPortal>
          </DropdownMenuSub>
          <DropdownMenuItem>GitHub</DropdownMenuItem>
          <DropdownMenuItem>Support</DropdownMenuItem>
          <DropdownMenuItem disabled>API</DropdownMenuItem>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

含危险操作

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { UploadIcon, Trash2Icon, PencilLineIcon } from "lucide-react"
export function DropdownMenuWithDestructive() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Align Start</Button>} />
      <DropdownMenuContent align="start" className="w-34">
        <DropdownMenuGroup>
          <DropdownMenuItem>
            <PencilLineIcon />
            Edit
          </DropdownMenuItem>
          <DropdownMenuItem>
            <UploadIcon />
            Share
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem variant="destructive">
            <Trash2Icon />
            <span>Delete</span>
          </DropdownMenuItem>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

带快捷键

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuWithShortcuts() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Align End</Button>} />
      <DropdownMenuContent align="end" className="w-66">
        <DropdownMenuGroup>
          <DropdownMenuItem>
            New Tab<DropdownMenuShortcut>⌘ + T</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuItem>
            New Window <DropdownMenuShortcut>⌘ + N</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem>
            New Incognito Window <DropdownMenuShortcut>⌘ + ⇧ + N</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuItem>
            History <DropdownMenuShortcut>⌘ + Y</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuItem>
            Downloads <DropdownMenuShortcut>⌥ + ⇧ + L</DropdownMenuShortcut>
          </DropdownMenuItem>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

优先级

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuPriority() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Bordered Menu</Button>} />
      <DropdownMenuContent className="w-56 shadow-none">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Task priority</DropdownMenuLabel>
          <DropdownMenuGroup>
            {priorityItemDefs.map((item, index) => (
              <DropdownMenuItem key={index}>
                <item.icon className={item.color} />
                {item.label}
              </DropdownMenuItem>
            ))}
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

带图标

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { UserIcon, SettingsIcon, DollarSignIcon, CircleHelpIcon, ReceiptIcon } from "lucide-react"
export function DropdownMenuWithIcons() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Menu item with icon</Button>} />
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>User Profile</DropdownMenuLabel>
          <DropdownMenuGroup>
            <DropdownMenuItem>
              <UserIcon />
              Profile
            </DropdownMenuItem>
            <DropdownMenuItem>
              <SettingsIcon />
              Settings
            </DropdownMenuItem>
            <DropdownMenuItem>
              <ReceiptIcon />
              Billing Plans
            </DropdownMenuItem>
            <DropdownMenuItem>
              <DollarSignIcon />
              Pricing
            </DropdownMenuItem>
            <DropdownMenuItem>
              <CircleHelpIcon />
              FAQ
            </DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

复选框

tsx
import { useState } from "react"
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuCheckboxItem } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuCheckboxes() {
  const [showStatusBar, setShowStatusBar] = useState(true)
  const [showActivityBar, setShowActivityBar] = useState(false)
  const [showPanel, setShowPanel] = useState(false)
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">With checkbox</Button>} />
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Appearance</DropdownMenuLabel>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar}>
          Status Bar
        </DropdownMenuCheckboxItem>
        <DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar} disabled>
          API
        </DropdownMenuCheckboxItem>
        <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>
          Invite users
        </DropdownMenuCheckboxItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

单选

tsx
import { useState } from "react"
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuRadioGroup, DropdownMenuRadioItem } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuRadio() {
  const [position, setPosition] = useState("bottom")
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">With radio</Button>} />
      <DropdownMenuContent className="w-56">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Panel Position</DropdownMenuLabel>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuRadioGroup value={position} onValueChange={setPosition}>
          <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
          <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
          <DropdownMenuRadioItem value="right" disabled>
            Right
          </DropdownMenuRadioItem>
        </DropdownMenuRadioGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

向左滑入

tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
export function DropdownMenuSlideLeft() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Slide Left Animation</Button>} />
      <DropdownMenuContent
        align="start"
        className="data-[state=closed]:slide-out-to-left-20 data-[state=open]:slide-in-from-left-20 data-[state=closed]:zoom-out-100 data-[state=open]:zoom-in-100 w-56 duration-400"
      >
        <DropdownMenuGroup>
          <DropdownMenuLabel>Settings</DropdownMenuLabel>
          <DropdownMenuGroup>
            <DropdownMenuItem>My Profile</DropdownMenuItem>
            <DropdownMenuItem>Settings</DropdownMenuItem>
            <DropdownMenuItem>Billing</DropdownMenuItem>
            <DropdownMenuItem>FAQs</DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuLabel>Contact</DropdownMenuLabel>
          <DropdownMenuGroup>
            <DropdownMenuItem>Call Support</DropdownMenuItem>
            <DropdownMenuItem>Chat with us</DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

向上滑入

tsx
import { useState } from "react"
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel } from "@polyui/react/dropdown-menu"
import { Button } from "@polyui/react/button"
import { Switch } from "@polyui/react/switch"
export function DropdownMenuSlideUp() {
  const [googleSwitch, setGoogleSwitch] = useState(false)
  const [twitterSwitch, setTwitterSwitch] = useState(false)
  const [linkedinSwitch, setLinkedinSwitch] = useState(false)
  const [dribbbleSwitch, setDribbbleSwitch] = useState(false)
  const [behanceSwitch, setBehanceSwitch] = useState(false)

  return (
    <DropdownMenu>
      <DropdownMenuTrigger render={<Button variant="outline">Slide Up Animation</Button>} />
      <DropdownMenuContent className="data-[state=closed]:slide-out-to-left-0 data-[state=open]:slide-in-from-left-0 data-[state=closed]:slide-out-to-bottom-20 data-[state=open]:slide-in-from-bottom-20 data-[state=closed]:zoom-out-100 w-56 duration-400">
        <DropdownMenuGroup>
          <DropdownMenuLabel>Apps notification</DropdownMenuLabel>
          <DropdownMenuGroup>
            <DropdownMenuItem className="justify-between" onSelect={(event) => event.preventDefault()}>
              <img
                src="https://cdn.shadcnstudio.com/ss-assets/components/dropdown/google.png"
                alt="google"
                className="size-4"
              />
              <span className="flex-1">Google</span>
              <Switch checked={googleSwitch} onCheckedChange={setGoogleSwitch} />
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between" onSelect={(event) => event.preventDefault()}>
              <img
                src="https://cdn.shadcnstudio.com/ss-assets/components/dropdown/twitter.png"
                alt="twitter"
                className="size-4"
              />
              <span className="flex-1">Twitter</span>
              <Switch checked={twitterSwitch} onCheckedChange={setTwitterSwitch} />
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between" onSelect={(event) => event.preventDefault()}>
              <img
                src="https://cdn.shadcnstudio.com/ss-assets/components/dropdown/linkedin.png"
                alt="linkedin"
                className="size-4"
              />
              <span className="flex-1">Linkedin</span>
              <Switch checked={linkedinSwitch} onCheckedChange={setLinkedinSwitch} />
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between" onSelect={(event) => event.preventDefault()}>
              <img
                src="https://cdn.shadcnstudio.com/ss-assets/components/dropdown/dribbble.png"
                alt="dribbble"
                className="size-4"
              />
              <span className="flex-1">Dribbble</span>
              <Switch checked={dribbbleSwitch} onCheckedChange={setDribbbleSwitch} />
            </DropdownMenuItem>
            <DropdownMenuItem className="justify-between" onSelect={(event) => event.preventDefault()}>
              <img
                src="https://cdn.shadcnstudio.com/ss-assets/components/dropdown/behance.png"
                alt="behance"
                className="size-4"
              />
              <span className="flex-1">Behance</span>
              <Switch checked={behanceSwitch} onCheckedChange={setBehanceSwitch} />
            </DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

属性

属性类型默认值说明
DropdownMenuContent › side"top" | "right" | "bottom" | "left""bottom"菜单相对触发器的弹出方向。
DropdownMenuContent › align"start" | "center" | "end""start"菜单相对触发器的对齐方式。
DropdownMenuContent › sideOffsetnumber4菜单与触发器之间的间距(px)。
DropdownMenuItem › variant"default" | "destructive""default"菜单项的视觉变体,destructive 显示为红色。
DropdownMenuItem › insetbooleanfalse添加左侧内边距,与带图标的菜单项对齐。