桌面应用程序中常见的视觉上持久存在的菜单,提供对一致命令集的快速访问。
import React from 'react';import * as Menubar from '@radix-ui/react-menubar';import { CheckIcon, ChevronRightIcon, DotFilledIcon } from '@radix-ui/react-icons';import './styles.css';const RADIO_ITEMS = ['Andy', 'Benoît', 'Luis'];const CHECK_ITEMS = ['Always Show Bookmarks Bar', 'Always Show Full URLs'];const MenubarDemo = () => {const [checkedSelection, setCheckedSelection] = React.useState([CHECK_ITEMS[1]]);const [radioSelection, setRadioSelection] = React.useState(RADIO_ITEMS[2]);return (<Menubar.Root className="MenubarRoot"><Menubar.Menu><Menubar.Trigger className="MenubarTrigger">File</Menubar.Trigger><Menubar.Portal><Menubar.Content className="MenubarContent" align="start" sideOffset={5} alignOffset={-3}><Menubar.Item className="MenubarItem">New Tab <div className="RightSlot">⌘ T</div></Menubar.Item><Menubar.Item className="MenubarItem">New Window <div className="RightSlot">⌘ N</div></Menubar.Item><Menubar.Item className="MenubarItem" disabled>New Incognito Window</Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Sub><Menubar.SubTrigger className="MenubarSubTrigger">Share<div className="RightSlot"><ChevronRightIcon /></div></Menubar.SubTrigger><Menubar.Portal><Menubar.SubContent className="MenubarSubContent" alignOffset={-5}><Menubar.Item className="MenubarItem">Email Link</Menubar.Item><Menubar.Item className="MenubarItem">Messages</Menubar.Item><Menubar.Item className="MenubarItem">Notes</Menubar.Item></Menubar.SubContent></Menubar.Portal></Menubar.Sub><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem">Print… <div className="RightSlot">⌘ P</div></Menubar.Item></Menubar.Content></Menubar.Portal></Menubar.Menu><Menubar.Menu><Menubar.Trigger className="MenubarTrigger">Edit</Menubar.Trigger><Menubar.Portal><Menubar.Content className="MenubarContent" align="start" sideOffset={5} alignOffset={-3}><Menubar.Item className="MenubarItem">Undo <div className="RightSlot">⌘ Z</div></Menubar.Item><Menubar.Item className="MenubarItem">Redo <div className="RightSlot">⇧ ⌘ Z</div></Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Sub><Menubar.SubTrigger className="MenubarSubTrigger">Find<div className="RightSlot"><ChevronRightIcon /></div></Menubar.SubTrigger><Menubar.Portal><Menubar.SubContent className="MenubarSubContent" alignOffset={-5}><Menubar.Item className="MenubarItem">Search the web…</Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem">Find…</Menubar.Item><Menubar.Item className="MenubarItem">Find Next</Menubar.Item><Menubar.Item className="MenubarItem">Find Previous</Menubar.Item></Menubar.SubContent></Menubar.Portal></Menubar.Sub><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem">Cut</Menubar.Item><Menubar.Item className="MenubarItem">Copy</Menubar.Item><Menubar.Item className="MenubarItem">Paste</Menubar.Item></Menubar.Content></Menubar.Portal></Menubar.Menu><Menubar.Menu><Menubar.Trigger className="MenubarTrigger">View</Menubar.Trigger><Menubar.Portal><Menubar.Content className="MenubarContent" align="start" sideOffset={5} alignOffset={-14} >{CHECK_ITEMS.map((item) => (<Menubar.CheckboxItem className="MenubarCheckboxItem inset" key={item} checked={checkedSelection.includes(item)} onCheckedChange={() => setCheckedSelection((current) => current.includes(item) ? current.filter((el) => el !== item) : current.concat(item) ) } ><Menubar.ItemIndicator className="MenubarItemIndicator"><CheckIcon /></Menubar.ItemIndicator>{item}</Menubar.CheckboxItem>))}<Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem inset">Reload <div className="RightSlot">⌘ R</div></Menubar.Item><Menubar.Item className="MenubarItem inset" disabled>Force Reload <div className="RightSlot">⇧ ⌘ R</div></Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem inset">Toggle Fullscreen</Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem inset">Hide Sidebar</Menubar.Item></Menubar.Content></Menubar.Portal></Menubar.Menu><Menubar.Menu><Menubar.Trigger className="MenubarTrigger">Profiles</Menubar.Trigger><Menubar.Portal><Menubar.Content className="MenubarContent" align="start" sideOffset={5} alignOffset={-14} ><Menubar.RadioGroup value={radioSelection} onValueChange={setRadioSelection}>{RADIO_ITEMS.map((item) => (<Menubar.RadioItem className="MenubarRadioItem inset" key={item} value={item}><Menubar.ItemIndicator className="MenubarItemIndicator"><DotFilledIcon /></Menubar.ItemIndicator>{item}</Menubar.RadioItem>))}<Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem inset">Edit…</Menubar.Item><Menubar.Separator className="MenubarSeparator" /><Menubar.Item className="MenubarItem inset">Add Profile…</Menubar.Item></Menubar.RadioGroup></Menubar.Content></Menubar.Portal></Menubar.Menu></Menubar.Root>);};export default MenubarDemo;
可以是受控的或不受控的。
支持具有可配置阅读方向的子菜单。
支持项目、标签和项目组。
支持可选中项目(单个或多个)。
自定义侧边、对齐方式、偏移量和碰撞处理。
可以选择渲染指向箭头。
焦点得到完全管理。
完整的键盘导航。
支持类型提示。
从命令行安装组件。
导入所有部分并将其组合在一起。
包含菜单栏的所有部分。
顶级菜单项,包含触发器和内容组合。
切换内容的按钮。默认情况下,Menubar.Content
将自身定位在触发器旁边。
使用时,将内容部分传送至 body
。
菜单打开时弹出的组件。
一个可选的箭头元素,用于与菜单栏菜单一起渲染。这可以用来帮助视觉上将触发器与 Menubar.Content
关联起来。必须在 Menubar.Content
内部渲染。
包含菜单栏项目的组件。
用于对多个 Menubar.Item
进行分组。
用于渲染标签。它无法使用方向键获得焦点。
可以像复选框一样控制和渲染的项目。
用于对多个 Menubar.RadioItem
进行分组。
可以像单选按钮一样控制和渲染的项目。
当父级 Menubar.CheckboxItem
或 Menubar.RadioItem
被选中时渲染。您可以直接设置此元素的样式,或者将其用作包装器以放入图标,或者两者兼而有之。
用于在菜单栏菜单中视觉上分隔项目。
包含子菜单的所有部分。
打开子菜单的项目。必须渲染在 Menubar.Sub
内部。
子菜单打开时弹出的组件。必须渲染在 Menubar.Sub
内部。
您可以通过结合使用 Menubar.Sub
及其各个部分来创建子菜单。
您可以通过 data-disabled
属性为禁用项目添加特殊样式。
使用 Separator
部分在项目之间添加分隔符。
使用 Label
部分帮助标记某个区域。
使用 CheckboxItem
部分添加可以选中的项目。
使用 RadioGroup
和 RadioItem
部分添加可以在其他项目中选中的项目。
您可以在 Item
部分添加额外的装饰元素,例如图像。
您可能希望约束内容(或子内容)的宽度,使其与触发器(或子触发器)的宽度匹配。您可能还想约束其高度,使其不超过视口。
我们公开了几个 CSS 自定义属性,例如 --radix-menubar-trigger-width
和 --radix-menubar-content-available-height
来支持此功能。使用它们来约束内容尺寸。
我们公开了 CSS 自定义属性 --radix-menubar-content-transform-origin
。使用它根据 side
、sideOffset
、align
、alignOffset
和任何冲突,从其计算出的原点开始为内容设置动画。
我们公开了 data-side
和 data-align
属性。它们的值将在运行时更改以反映冲突。使用它们创建基于冲突和方向的动画。
遵循 菜单按钮 WAI-ARIA 设计模式 并使用 循环 Tab 键索引 来管理菜单项之间的焦点移动。