import { DropdownMenu, Button } from "@cloudflare/kumo";
import { PlusIcon } from "@phosphor-icons/react";
export function DropdownBasicDemo() {
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button icon={PlusIcon}>Add</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item>Worker</DropdownMenu.Item>
<DropdownMenu.Item>Pages</DropdownMenu.Item>
<DropdownMenu.Item>KV Namespace</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}安装
批量导入
import { DropdownMenu } from "@cloudflare/kumo";按需导入
import { DropdownMenu } from "@cloudflare/kumo/components/dropdown";用法
import { DropdownMenu, Button } from "@cloudflare/kumo";
export default function Example() {
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>Menu</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item onClick={() => console.log("edit")}>
Edit
</DropdownMenu.Item>
<DropdownMenu.Item onClick={() => console.log("duplicate")}>
Duplicate
</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item
variant="danger"
onClick={() => console.log("delete")}
>
Delete
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}示例
基本下拉
import { DropdownMenu, Button } from "@cloudflare/kumo";
import { PlusIcon } from "@phosphor-icons/react";
export function DropdownBasicDemo() {
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button icon={PlusIcon}>Add</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item>Worker</DropdownMenu.Item>
<DropdownMenu.Item>Pages</DropdownMenu.Item>
<DropdownMenu.Item>KV Namespace</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}缩进条目
在没有图标的条目上使用 inset,可让其文本与带图标的条目对齐。
import { DropdownMenu, Button } from "@cloudflare/kumo";
import { CopyIcon, PencilSimpleIcon, TrashIcon } from "@phosphor-icons/react";
/**
* Use `inset` on items without an icon to align their text with items that have one.
*/
export function DropdownInsetDemo() {
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>Edit</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item icon={PencilSimpleIcon}>Rename</DropdownMenu.Item>
<DropdownMenu.Item icon={CopyIcon}>Duplicate</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item inset>Move to folder</DropdownMenu.Item>
<DropdownMenu.Item inset>Add to favorites</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item icon={TrashIcon} variant="danger">
Delete
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}处理条目点击
使用 DropdownMenu.Item 上的 onClick 处理操作。每个条目都会接收到标准的 React 鼠标事件处理器。
import { useState } from "react";
import { DropdownMenu, Button } from "@cloudflare/kumo";
import { CopyIcon, PencilSimpleIcon, TrashIcon } from "@phosphor-icons/react";
/**
* Use `onClick` on `DropdownMenu.Item` to handle item actions.
* Each item receives a standard React mouse event handler.
*/
export function DropdownOnClickDemo() {
const [lastAction, setLastAction] = useState<string | null>(null);
return (
<div className="flex flex-col items-start gap-2">
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>Actions</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item
icon={CopyIcon}
onClick={() => setLastAction("Duplicated")}
>
Duplicate
</DropdownMenu.Item>
<DropdownMenu.Item
icon={PencilSimpleIcon}
onClick={() => setLastAction("Renamed")}
>
Rename
</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item
icon={TrashIcon}
variant="danger"
onClick={() => setLastAction("Deleted")}
>
Delete
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
{lastAction && (
<p className="text-sm text-kumo-subtle">
Last action: <span className="text-kumo-default">{lastAction}</span>
</p>
)}
</div>
);
}复选框条目
使用 DropdownMenu.CheckboxItem 实现可独立勾选或取消勾选的可切换选项。
import { useState } from "react";
import { DropdownMenu, Button } from "@cloudflare/kumo";
export function DropdownCheckboxDemo() {
const [showSidebar, setShowSidebar] = useState(true);
const [showLineNumbers, setShowLineNumbers] = useState(false);
const [wordWrap, setWordWrap] = useState(true);
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>View Options</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Group>
<DropdownMenu.Label>Display</DropdownMenu.Label>
<DropdownMenu.CheckboxItem
checked={showSidebar}
onCheckedChange={setShowSidebar}
>
Show sidebar
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={showLineNumbers}
onCheckedChange={setShowLineNumbers}
>
Show line numbers
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={wordWrap}
onCheckedChange={setWordWrap}
>
Word wrap
</DropdownMenu.CheckboxItem>
</DropdownMenu.Group>
</DropdownMenu.Content>
</DropdownMenu>
);
}带单选的内嵌菜单
使用 DropdownMenu.Sub、DropdownMenu.SubTrigger 和
DropdownMenu.SubContent 创建嵌套子菜单。对于语言、时区等单选列表,
请使用 DropdownMenu.RadioGroup 和
DropdownMenu.RadioItem。
import { useState } from "react";
import { DropdownMenu, Button } from "@cloudflare/kumo";
import { UserIcon, CreditCardIcon, MoonIcon, SignOutIcon } from "@phosphor-icons/react";
export function DropdownNestedDemo() {
const [language, setLanguage] = useState("en");
const [timezone, setTimezone] = useState("America/Los_Angeles");
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button icon={UserIcon}>Account</Button>} />
<DropdownMenu.Content>
<DropdownMenu.Item icon={UserIcon}>Profile</DropdownMenu.Item>
<DropdownMenu.Item icon={CreditCardIcon}>Billing</DropdownMenu.Item>
<DropdownMenu.Item icon={MoonIcon}>Dark mode</DropdownMenu.Item>
{/* Language submenu with RadioGroup */}
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Language</DropdownMenu.SubTrigger>
<DropdownMenu.SubContent>
<DropdownMenu.Group>
<DropdownMenu.RadioGroup
value={language}
onValueChange={setLanguage}
>
{languages.map((lang) => (
<DropdownMenu.RadioItem key={lang.code} value={lang.code}>
{lang.label}
<DropdownMenu.RadioItemIndicator />
</DropdownMenu.RadioItem>
))}
</DropdownMenu.RadioGroup>
</DropdownMenu.Group>
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
{/* Timezone submenu with RadioGroup */}
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Set Timezone</DropdownMenu.SubTrigger>
<DropdownMenu.SubContent>
<DropdownMenu.Group>
<DropdownMenu.RadioGroup
value={timezone}
onValueChange={setTimezone}
>
{timezones.map((tz) => (
<DropdownMenu.RadioItem key={tz.value} value={tz.value}>
{tz.label}
<DropdownMenu.RadioItemIndicator />
</DropdownMenu.RadioItem>
))}
</DropdownMenu.RadioGroup>
</DropdownMenu.Group>
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
<DropdownMenu.Separator />
<DropdownMenu.Item icon={SignOutIcon} variant="danger">
Log out
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}带头像的自定义触发器
使用 render 属性自定义触发器元素,同时传入要渲染在其中的子内容。
当需要将头像等非按钮触发器包裹在无障碍按钮元素中时,此功能非常实用。
import { DropdownMenu } from "@cloudflare/kumo";
import { UserIcon, SignOutIcon, GearIcon } from "@phosphor-icons/react";
/**
* Demonstrates using the render prop with children to compose a custom trigger
* that contains other elements. The render prop provides the trigger element,
* while children are rendered inside it.
*/
export function DropdownAvatarTriggerDemo() {
return (
<DropdownMenu>
<DropdownMenu.Trigger
render={<button type="button" className="rounded-full" />}
>
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-kumo-brand text-sm font-medium text-white">
MR
</span>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item icon={UserIcon}>Profile</DropdownMenu.Item>
<DropdownMenu.Item icon={GearIcon}>Settings</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item icon={SignOutIcon} variant="danger">
Log out
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
);
}导航链接
使用 DropdownMenu.LinkItem 处理导航到 URL 的菜单条目。
它会渲染语义化的 <a> 元素,可完全控制 target、rel 等链接属性。
import { DropdownMenu, Button } from "@cloudflare/kumo";
import { GearIcon, BookOpenIcon, ArrowSquareOutIcon } from "@phosphor-icons/react";
/**
* Demonstrates the new LinkItem component for navigation links.
* Use LinkItem instead of Item with href for cleaner, more semantic links.
*/
export function DropdownLinkItemDemo() {
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>Resources</Button>} />
<DropdownMenu.Content>
<DropdownMenu.LinkItem href="/settings" icon={GearIcon}>
Settings
</DropdownMenu.LinkItem>
<DropdownMenu.LinkItem href="/docs" icon={BookOpenIcon}>
Documentation
</DropdownMenu.LinkItem>
<DropdownMenu.Separator />
<DropdownMenu.LinkItem
href="https://developers.cloudflare.com"
target="_blank"
icon={ArrowSquareOutIcon}
>
Developer Docs
</DropdownMenu.LinkItem>
</DropdownMenu.Content>
</DropdownMenu>
);
}长列表
当下拉包含大量条目时,内容会自动将高度限制为可用的视口空间, 并变为可滚动。
import { DropdownMenu, Button } from "@cloudflare/kumo";
/**
* A dropdown with a very long list of items to demonstrate the max-height
* behavior — the content scrolls when it exceeds available viewport space.
*/
export function DropdownLongListDemo() {
const items = Array.from({ length: 30 }, (_, i) => `Option ${i + 1}`);
return (
<DropdownMenu>
<DropdownMenu.Trigger render={<Button>Open long list</Button>} />
<DropdownMenu.Content>
{items.map((item) => (
<DropdownMenu.Item key={item}>{item}</DropdownMenu.Item>
))}
</DropdownMenu.Content>
</DropdownMenu>
);
}API 参考
DropdownMenu
管理下拉状态的主组件。
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "danger" | "default" | Visual style of the dropdown item. - `"default"` — Standard item appearance - `"danger"` — Destructive action with red text |
DropdownMenu.Trigger
点击即可打开下拉的按钮。
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
DropdownMenu.Item
用于操作的单个菜单条目。
| Prop | Type | Default | Description |
|---|---|---|---|
| icon | Icon | ReactNode | - | Icon displayed before the label. |
| variant | "default" | "danger" | "default" | Visual style of the item. |
| selected | boolean | - | Shows a check mark indicator when true. |
| inset | boolean | - | Adds left padding to align with items that have icons. |
| onClick | (event: React.MouseEvent) => void | - | Callback when the item is clicked. |
| closeOnClick | boolean | true | Whether the menu closes after clicking this item. |
| disabled | boolean | - | When true, the item cannot be interacted with. |
DropdownMenu.LinkItem
导航到 URL 的菜单条目。渲染语义化的 <a> 元素。导航链接请使用此组件,而不是 Item。
| Prop | Type | Default | Description |
|---|---|---|---|
| href | string | - | URL to navigate to when clicked. |
| icon | Icon | ReactNode | - | Icon displayed before the label. |
| variant | "default" | "danger" | "default" | Visual style of the item. |
| inset | boolean | - | Adds left padding to align with items that have icons. |
| target | string | - | Link target attribute (e.g. "_blank" for new tab). |
| render | ReactElement | ((props, state) => ReactElement) | - | Custom element to render as the link. Use to integrate with framework routers (e.g. Next.js Link). |
DropdownMenu.CheckboxItem
可开启或关闭的菜单条目。适用于独立的布尔选项。
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | - | Whether the item is checked. |
| defaultChecked | boolean | false | Whether the item is initially checked (uncontrolled). |
| onCheckedChange | (checked: boolean, event: ChangeEventDetails) => void | - | Callback when the checked state changes. |
| closeOnClick | boolean | false | Whether the menu closes after clicking this item. |
| disabled | boolean | - | When true, the item cannot be interacted with. |
DropdownMenu.Sub
嵌套子菜单的主组件。将 SubTrigger 和 SubContent 包裹在此组件内。
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
DropdownMenu.SubTrigger
悬停或点击时打开嵌套子菜单的菜单条目。自动显示插入标记(caret)图标。
| Prop | Type | Default | Description |
|---|---|---|---|
| icon | Icon | - | Icon displayed before the label. |
| inset | boolean | - | Adds left padding to align with items that have icons. |
DropdownMenu.SubContent
子菜单条目的容器。相对于 SubTrigger 定位。
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
DropdownMenu.Separator
菜单条目之间的视觉分隔线。
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
DropdownMenu.RadioGroup
对单选条目分组以实现单选行为。一次只能选中一个条目。
| Prop | Type | Default | Description |
|---|---|---|---|
| value | any | - | The controlled value of the currently selected radio item. |
| defaultValue | any | - | The initially selected value (uncontrolled). |
| onValueChange | (value: any, event: ChangeEventDetails) => void | - | Callback when the selected value changes. |
| disabled | boolean | - | When true, all radio items in the group are disabled. |
DropdownMenu.RadioItem
行为类似单选按钮的菜单条目。必须在 RadioGroup 内使用。
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | any | - | The value of this radio item. |
| icon | Icon | ReactNode | - | Icon displayed before the label. |
| inset | boolean | - | Adds left padding to align with items that have icons. |
| closeOnClick | boolean | false | Whether the menu closes after clicking this item. |
| disabled | boolean | - | When true, the item cannot be interacted with. |
DropdownMenu.RadioItemIndicator
显示 RadioItem 的选中状态。默认显示对勾。
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.