Components

上下文菜单

显示一个位于指针位置的菜单,由右键单击或长按触发。

import * as React from "react";
import { ContextMenu } from "radix-ui";
import { DotFilledIcon, CheckIcon, ChevronRightIcon, } from "@radix-ui/react-icons";
import "./styles.css";
const ContextMenuDemo = () => {
const [bookmarksChecked, setBookmarksChecked] = React.useState(true);
const [urlsChecked, setUrlsChecked] = React.useState(false);
const [person, setPerson] = React.useState("pedro");
return (
<ContextMenu.Root>
<ContextMenu.Trigger className="ContextMenuTrigger">
Right-click here.
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent" sideOffset={5} align="end" >
<ContextMenu.Item className="ContextMenuItem">
Back <div className="RightSlot">⌘+[</div>
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem" disabled>
Forward <div className="RightSlot">⌘+]</div>
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem">
Reload <div className="RightSlot">⌘+R</div>
</ContextMenu.Item>
<ContextMenu.Sub>
<ContextMenu.SubTrigger className="ContextMenuSubTrigger">
More Tools
<div className="RightSlot">
<ChevronRightIcon />
</div>
</ContextMenu.SubTrigger>
<ContextMenu.Portal>
<ContextMenu.SubContent className="ContextMenuSubContent" sideOffset={2} alignOffset={-5} >
<ContextMenu.Item className="ContextMenuItem">
Save Page As… <div className="RightSlot">⌘+S</div>
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem">
Create Shortcut…
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem">
Name Window…
</ContextMenu.Item>
<ContextMenu.Separator className="ContextMenuSeparator" />
<ContextMenu.Item className="ContextMenuItem">
Developer Tools
</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Portal>
</ContextMenu.Sub>
<ContextMenu.Separator className="ContextMenuSeparator" />
<ContextMenu.CheckboxItem className="ContextMenuCheckboxItem" checked={bookmarksChecked} onCheckedChange={setBookmarksChecked} >
<ContextMenu.ItemIndicator className="ContextMenuItemIndicator">
<CheckIcon />
</ContextMenu.ItemIndicator>
Show Bookmarks <div className="RightSlot">⌘+B</div>
</ContextMenu.CheckboxItem>
<ContextMenu.CheckboxItem className="ContextMenuCheckboxItem" checked={urlsChecked} onCheckedChange={setUrlsChecked} >
<ContextMenu.ItemIndicator className="ContextMenuItemIndicator">
<CheckIcon />
</ContextMenu.ItemIndicator>
Show Full URLs
</ContextMenu.CheckboxItem>
<ContextMenu.Separator className="ContextMenuSeparator" />
<ContextMenu.Label className="ContextMenuLabel">
People
</ContextMenu.Label>
<ContextMenu.RadioGroup value={person} onValueChange={setPerson}>
<ContextMenu.RadioItem className="ContextMenuRadioItem" value="pedro" >
<ContextMenu.ItemIndicator className="ContextMenuItemIndicator">
<DotFilledIcon />
</ContextMenu.ItemIndicator>
Pedro Duarte
</ContextMenu.RadioItem>
<ContextMenu.RadioItem className="ContextMenuRadioItem" value="colm" >
<ContextMenu.ItemIndicator className="ContextMenuItemIndicator">
<DotFilledIcon />
</ContextMenu.ItemIndicator>
Colm Tuite
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
};
export default ContextMenuDemo;

Features

    支持可配置阅读方向的子菜单。

    支持项目、标签和项目组。

    支持可选的不确定状态的可检查项目(单个或多个)。

    支持模态和非模态模式。

    自定义侧边、对齐方式、偏移量和碰撞处理。

    焦点完全管理。

    全键盘导航。

    支持类型预判。

    取消和分层行为高度可定制。

    在触摸设备上通过长按触发

安装

从命令行安装组件。

npm install @radix-ui/react-context-menu

结构

导入所有部件并将它们组合在一起。

import { ContextMenu } from "radix-ui";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger />
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label />
<ContextMenu.Item />
<ContextMenu.Group>
<ContextMenu.Item />
</ContextMenu.Group>
<ContextMenu.CheckboxItem>
<ContextMenu.ItemIndicator />
</ContextMenu.CheckboxItem>
<ContextMenu.RadioGroup>
<ContextMenu.RadioItem>
<ContextMenu.ItemIndicator />
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Sub>
<ContextMenu.SubTrigger />
<ContextMenu.Portal>
<ContextMenu.SubContent />
</ContextMenu.Portal>
</ContextMenu.Sub>
<ContextMenu.Separator />
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);

API 参考

遵循 菜单 WAI-ARIA 设计模式 并使用 游走的 tabindex 来管理菜单项之间的焦点移动。

包含上下文菜单的所有部分。

PropTypeDefault
dir
enum
No default value
onOpenChange
function
No default value
modal
boolean
true

触发器

打开上下文菜单的区域。在右键单击(或使用相关的键盘快捷键)时,将其包裹在您希望上下文菜单打开的目标周围。

PropTypeDefault
asChild
boolean
false
disabled
boolean
false
Data attributeValues
[data-state]"open" | "closed"

门户

使用时,将内容部分门户到 body 中。

PropTypeDefault
forceMount
boolean
No default value
container
HTMLElement
document.body

内容

在打开的上下文菜单中弹出的组件。

PropTypeDefault
asChild
boolean
false
loop
boolean
false
onCloseAutoFocus
function
No default value
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
onFocusOutside
function
No default value
onInteractOutside
function
No default value
forceMount
boolean
No default value
alignOffset
number
0
avoidCollisions
boolean
true
collisionBoundary
Boundary
[]
collisionPadding
number | Padding
0
sticky
enum
"partial"
hideWhenDetached
boolean
false
Data attributeValues
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS VariableDescription
--radix-context-menu-content-transform-origin从内容和箭头位置/偏移计算的 transform-origin
--radix-context-menu-content-available-width触发器和边界边缘之间的剩余宽度
--radix-context-menu-content-available-height触发器和边界边缘之间的剩余高度
--radix-context-menu-trigger-width触发器的宽度
--radix-context-menu-trigger-height触发器的高度

箭头

可选的箭头元素,用于在子菜单旁边渲染。它可以用于帮助在视觉上将触发项目与 ContextMenu.Content 连接。必须在 ContextMenu.Content 内部渲染。

PropTypeDefault
asChild
boolean
false
width
number
10
height
number
5

项目

包含上下文菜单项的组件。

PropTypeDefault
asChild
boolean
false
disabled
boolean
No default value
onSelect
function
No default value
textValue
string
No default value
Data attributeValues
[data-highlighted]

当高亮时存在

[data-disabled]

当禁用时存在

用于将多个 ContextMenu.Item 分组。

PropTypeDefault
asChild
boolean
false

标签

用于渲染标签。它不能使用箭头键获得焦点。

PropTypeDefault
asChild
boolean
false

复选框项目

可以像复选框一样控制和渲染的项目。

PropTypeDefault
asChild
boolean
false
checked
boolean | 'indeterminate'
No default value
onCheckedChange
function
No default value
disabled
boolean
No default value
onSelect
function
No default value
textValue
string
No default value
Data attributeValues
[data-state]"checked" | "unchecked" | "indeterminate"
[data-highlighted]

当高亮时存在

[data-disabled]

当禁用时存在

单选组

用于将多个 ContextMenu.RadioItem 分组。

PropTypeDefault
asChild
boolean
false
value
string
No default value
onValueChange
function
No default value

单选项

可以像单选框一样控制和渲染的项目。

PropTypeDefault
asChild
boolean
false
value*
string
No default value
disabled
boolean
No default value
onSelect
function
No default value
textValue
string
No default value
Data attributeValues
[data-state]"checked" | "unchecked" | "indeterminate"
[data-highlighted]

当高亮时存在

[data-disabled]

当禁用时存在

项目指示器

当父级 ContextMenu.CheckboxItemContextMenu.RadioItem 被选中时渲染。您可以直接为此元素设置样式,或者将其用作放置图标的包装器,或者两者兼有。

PropTypeDefault
asChild
boolean
false
forceMount
boolean
No default value
Data attributeValues
[data-state]"checked" | "unchecked" | "indeterminate"

分隔符

用于在上下文菜单中视觉上分隔项目。

PropTypeDefault
asChild
boolean
false

包含子菜单的所有部分。

PropTypeDefault
defaultOpen
boolean
No default value
open
boolean
No default value
onOpenChange
function
No default value

子触发器

打开子菜单的项目。必须在 ContextMenu.Sub 内部渲染。

PropTypeDefault
asChild
boolean
false
disabled
boolean
No default value
textValue
string
No default value
Data attributeValues
[data-state]"open" | "closed"
[data-highlighted]

当高亮时存在

[data-disabled]

当禁用时存在

子内容

当子菜单打开时弹出的组件。必须在 ContextMenu.Sub 内部渲染。

PropTypeDefault
asChild
boolean
false
loop
boolean
false
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
onFocusOutside
function
No default value
onInteractOutside
function
No default value
forceMount
boolean
No default value
sideOffset
number
0
alignOffset
number
0
avoidCollisions
boolean
true
collisionBoundary
Boundary
[]
collisionPadding
number | Padding
0
arrowPadding
number
0
sticky
enum
"partial"
hideWhenDetached
boolean
false
Data attributeValues
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS VariableDescription
--radix-context-menu-content-transform-origin从内容和箭头位置计算的 transform-origin
--radix-context-menu-content-available-width触发器和边界边缘之间的剩余宽度
--radix-context-menu-content-available-height触发器和边界边缘之间的剩余高度
--radix-context-menu-trigger-width触发器的宽度
--radix-context-menu-trigger-height触发器的高度

示例

带子菜单

您可以通过结合使用 ContextMenu.Sub 和其部分来创建子菜单。

<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>子菜单 →</ContextMenu.SubTrigger>
<ContextMenu.Portal>
<ContextMenu.SubContent>
<ContextMenu.Item>子菜单项目</ContextMenu.Item>
<ContextMenu.Item>子菜单项目</ContextMenu.Item>
<ContextMenu.Arrow />
</ContextMenu.SubContent>
</ContextMenu.Portal>
</ContextMenu.Sub>
<ContextMenu.Separator />
<ContextMenu.Item></ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>

带禁用项目

您可以通过 data-disabled 属性为禁用项目添加特殊样式。

// index.jsx
import { ContextMenu } from "radix-ui";
import "./styles.css";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item className="ContextMenuItem" disabled>
</ContextMenu.Item>
<ContextMenu.Item className="ContextMenuItem"></ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuItem[data-disabled] {
color: gainsboro;
}

带分隔符

使用 Separator 部分在项目之间添加分隔符。

<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item></ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>

带标签

使用 Label 部分帮助标记一个部分。

<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Label>标签</ContextMenu.Label>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Item></ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>

带复选框项目

使用 CheckboxItem 部分添加一个可被选中的项目。

import * as React from "react";
import { CheckIcon } from "@radix-ui/react-icons";
import { ContextMenu } from "radix-ui";
export default () => {
const [checked, setChecked] = React.useState(true);
return (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Item></ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.CheckboxItem checked={checked} onCheckedChange={setChecked} >
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
复选框项目
</ContextMenu.CheckboxItem>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
};

带单选项目

使用 RadioGroupRadioItem 部分添加一个可以在其他项目中选中的项目。

import * as React from "react";
import { CheckIcon } from "@radix-ui/react-icons";
import { ContextMenu } from "radix-ui";
export default () => {
const [color, setColor] = React.useState("blue");
return (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.RadioGroup value={color} onValueChange={setColor}>
<ContextMenu.RadioItem value="red">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
红色
</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="blue">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
蓝色
</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="green">
<ContextMenu.ItemIndicator>
<CheckIcon />
</ContextMenu.ItemIndicator>
绿色
</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
};

带复杂项目

您可以在 Item 部分中添加额外的装饰元素,例如图像。

import { ContextMenu } from "radix-ui";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content>
<ContextMenu.Item>
<img src="" />
阿道夫·赫斯
</ContextMenu.Item>
<ContextMenu.Item>
<img src="" />
米亚·迈尔斯
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);

限制内容/子内容大小

您可能希望限制内容(或子内容)的宽度,以使其匹配触发器(或子触发器)的宽度。您也可以希望限制其高度,以不超过视口。

我们暴露了几个 CSS 自定义属性,例如 --radix-context-menu-trigger-width--radix-context-menu-content-available-height 来支持这一点。使用它们来限制内容大小。

// index.jsx
import { ContextMenu } from "radix-ui";
import "./styles.css";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
width: var(--radix-context-menu-trigger-width);
max-height: var(--radix-context-menu-content-available-height);
}

基于位置的动画

我们暴露了一个 CSS 自定义属性 --radix-context-menu-content-transform-origin。使用它根据 sidesideOffsetalignalignOffset 和任何碰撞从其计算的原点动画内容。

// index.jsx
import { ContextMenu } from "radix-ui";
import "./styles.css";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
transform-origin: var(--radix-context-menu-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}

基于碰撞的动画

我们暴露了 data-sidedata-align 属性。它们的值在运行时将变化以反映碰撞。使用它们来创建基于碰撞和方向的动画。

// index.jsx
import { ContextMenu } from "radix-ui";
import "./styles.css";
export default () => (
<ContextMenu.Root>
<ContextMenu.Trigger></ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content className="ContextMenuContent">
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
);
/* styles.css */
.ContextMenuContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.ContextMenuContent[data-side="top"] {
animation-name: slideUp;
}
.ContextMenuContent[data-side="bottom"] {
animation-name: slideDown;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

可访问性

使用 游走的 tabindex 来管理菜单项之间的焦点移动。

键盘交互

KeyDescription
Space
激活焦点项。
Enter
激活焦点项。
ArrowDown
将焦点移动到下一个项目。
ArrowUp
将焦点移动到上一个项目。
ArrowRightArrowLeft
当焦点位于 ContextMenu.SubTrigger 时,根据阅读方向打开或关闭子菜单。
Esc
关闭上下文菜单