生态产品多个设计器现已发布正式版

查看生态总览
跳转到内容

Menu 菜单 ​

从触发器打开一组操作命令。

用法 ​

从按钮打开一组操作

组件结构 ​

加粗的是必需部件。

data-scope="menu":trigger · positioner · content · item · item-icon · item-text · item-description · item-shortcut · item-suffix · item-indicator · separator · group · group-label · arrow

示例 ​

图标与快捷键 ​

为常用命令补充识别信息

分组 ​

使用标题与分隔线组织命令

子菜单 ​

将相关操作收进下一层

破坏性命令 ​

用语气把删除一类命令与其余区分开

说明与快捷键 ​

只交数据,副文本与按键提示自动落位

选择型条目 ​

CheckboxItem 与 RadioGroup 修改持久设置,切换后菜单保持展开

设计指引 ​

何时使用 ​

  • 收纳次要操作、账户命令或多级命令。

何时不用 ​

特性 ​

  • collection 可直接生成条目、分组、图标、说明、快捷键提示和分隔线。条目的 icon 是图标记录,铺进文字之前的 item-icon(装饰态,读屏从条目文字取意),item-prefix 插槽也落在这一格、压过 icon。同一层(跨分组与分隔线,子菜单另算)里只要有一条带图标,所有条目都空出图标那一格,正文左缘对齐;整层都没有图标就不留。勾选与单选条目的勾在 item-indicator,两者各占一格。勾选与单选条目的勾是条目的最后一个部件,排在正文、说明与快捷键之后,与子菜单箭头同列,图标与普通条目左缘对齐;手写部件时写在哪都排到行尾。同一层有勾选条目时,普通条目的快捷键与它们同列。
  • 只给 collection 时照标准结构铺:触发按钮(内容归作者,没写时取 label),定位层里的条目、分组与分隔线;带 children 的条目是一个嵌套的子菜单,它的触发条目与普通条目一样铺:图标取 icon(铺进 item-icon),文字取 label(铺进 item-text)。Vue / React 不写默认插槽与 Web Components 不写部件时生成的节点出自同一个结构函数;Web Components 的部件直接长在 <xh-menu> 里,触发按钮的内容与条目可用宿主直接子节点 slot="trigger"、slot="item:<值>" 等接管(只到根菜单这一层),子菜单生成嵌套的 <xh-menu submenu>,触发条目写着它的 value。指向锚点的箭头要手写结构时自己摆。
  • anchor 换成外部锚点:由别处的按钮(工具栏命令等)受控打开时,把那颗按钮交给 anchor,菜单就贴着它定位、收起时焦点归还给它;按数据铺设时不再铺触发按钮。展开期间这颗按钮带 aria-haspopup、aria-expanded 与 aria-controls,收起或换锚点时还原;点它算菜单内的交互,开合交给打开它的那条命令。没有触发器替菜单命名,名字写在 translations.content 上。
  • 触发按钮里只放图标(皮肤画的字形,没有文字)时,名字写在 translations.trigger 上,落成按钮的 aria-label;菜单容器经 aria-labelledby 指回触发器,跟着取到同一个名字。表格数据驱动模式下列头里的筛选钮就是这样一颗菜单。
  • 条目可逐条声明语气,删除一类命令自带该族字色与高亮底。
  • 快捷键提示贴行尾,与说明同档同色;它是纯装饰,读屏从命令文字取意。要读屏念出快捷键,条目再写 keyshortcuts,落成条目的 aria-keyshortcuts。
  • 支持方向键、首字符检索、禁用条目和多级子菜单。数据驱动时节点写 children 即为子菜单入口,Vue / React 的默认树按 children 递归铺出下一层,深度不限,路由菜单这类按数据生成的多级菜单不必手写 Sub 部件;子层与本层同用 item / item-prefix / item-suffix 插槽,叶子的选中汇到根级 item-select。入口只能是普通条目,勾选与单选条目带 children 直接报错。子菜单那一层的勾选值与单选值写在带 children 的条目上(checkboxValue / radioValue),与子菜单自己的同名属性同义,写了即受控;按数据铺时子层的勾选改动不另外上报,勾选条目写 closeOnSelect,由根上的 item-select 得知。
  • 子菜单使用安全三角避免指针斜向移动时误关闭。
  • 内容高度缺省以 20rem 一档封顶,--xh-menu-max-h 可改;写 fitAvailableHeight 则只按落定那一侧的可用高度封顶,菜单栏的子菜单由菜单栏自动带上。
  • 条目可组合图标、文字、说明和快捷键提示。
  • CheckboxItem 与 RadioGroup / RadioItem 表达菜单内的持久选项,值分别由 checkboxValue 与 radioValue 控制;默认切换后保持展开,逐条可用 closeOnSelect 改为收起。
  • 行首与行尾两格各有逐条钩子,只想加个图标不必把整条重搭;item 插槽仍是整条的接管口。
  • 选中命令后发出根级 item-select 并关闭菜单链。

组合 ​

  • 触发器通常使用中性按钮,避免与页面主操作争夺层级。

最佳实践 ​

  • 破坏性命令放在末尾、与普通命令分隔,并同时给出 danger 语气和图标。
  • 条目使用简短的动宾短语。
  • 仅为已注册的快捷键显示提示。
  • 一组选项只能取其一时使用 RadioGroup,不用多个互不关联的 CheckboxItem 模拟。

反模式 ​

  • 不要用命令菜单代替持久选择控件。
  • 不要在菜单中放置长段说明或复杂表单。

API 参考 ​

产物 ​

层值
自定义元素<xh-menu>
Vue 组件XhMenuArrow XhMenuCheckboxItem XhMenuContent XhMenuGroup XhMenuGroupLabel XhMenuItem XhMenuItemDescription XhMenuItemIcon XhMenuItemIndicator XhMenuItemShortcut XhMenuItemSuffix XhMenuItemText XhMenuPositioner XhMenuRadioGroup XhMenuRadioItem XhMenuRoot XhMenuSeparator XhMenuSub XhMenuSubTrigger XhMenuTrigger
组合式函数useMenu
状态机menuMachine
皮肤@xihan-ui/styles/menu.css

Props ​

属性类型必填说明
collectionMenuNode[]条目数据,显示文本、禁用、逐条语气与分组的事实源。提供后条目部件只需声明 value。 未提供时回到这些事实都写在条目部件上的方式(语气写成条目的 data-tone)。
checkboxValuestring[]checkbox 条目的选中集合;提供即受控。
defaultCheckboxValuestring[]
radioValueMenuRadioValueRadioGroup 身份到当前条目值的映射;提供即受控。
defaultRadioValueMenuRadioValue
openboolean展开态,提供即受控;受控下内部不自行修改,只发 onOpenChange。
defaultOpenboolean
anchorHTMLElement | null外部锚点:给了就锚在它上面、收起时焦点归还到它,不再取 trigger;用于由别处的按钮受控打开菜单,按数据铺设时不再铺触发按钮。 展开期间它带 aria-haspopup、aria-expanded、aria-controls,收起或换锚点时还原;点它算层内交互,不会先被判为层外交互关掉。 content 不再由触发器命名,名字写在 translations.content 上。只用于根菜单。
placementPlacement
offsetnumber
loopboolean方向键到达末尾是否回绕,默认 true。
dirDirection文字方向,默认 ltr。
toneTone整张菜单的语气:brand / neutral / success / warning / danger / info。 只为浮层与作者放进来的内容备好该族颜色,不下发给条目——条目保持中性档, 逐条的语气写在 collection 的 tone 上(见 MenuNode)。
sizeSize尺寸:sm / md / lg,决定条目高度、内边距与字号档位。
fitAvailableHeightboolean内容只按落定那一侧的可用高度封顶,不叠菜单的固定上限(20rem 一档);作者写的 --xh-menu-max-h 照样生效。 菜单栏的子菜单由菜单栏传入,再往下一层跟着上一层;单独用的菜单一般不写。
typeaheadboolean首字符连打检索,默认开启。
disabledboolean整张菜单禁用:触发器不再展开,条目全部为 aria-disabled。
translationsPartial<MenuTranslations>
submenuboolean本菜单是另一张菜单的子菜单:触发器渲染为父菜单的条目形态 (经 getSubmenuTriggerProps),默认落位改为侧向,悬停触发默认开启。
openOnHoverboolean悬停触发:进入触发器延时展开、经安全三角离开才收起。子菜单默认开启,普通菜单默认关闭。
hoverOpenDelaynumber悬停到展开的延时(ms),默认 100。
hoverCloseDelaynumber离开到收起的延时(ms),也是安全三角中的停滞上限,默认 300。
onOpenChange(details: MenuOpenChangeDetails) => voidopen 变化回调。
onItemSelect(details: MenuItemSelectDetails) => void条目被选中;菜单随之关闭。
onCheckboxValueChange(details: MenuCheckboxValueChangeDetails) => void
onRadioValueChange(details: MenuRadioValueChangeDetails) => void

collection 的元素。

字段类型必填说明
valuestring是
kindMenuChoiceKind条目语义;普通命令缺省为 item。radio 条目必须同时声明 group。
labelstring展示文本;默认回退为 value。
disabledboolean条目禁用:方向键跳过它,但它仍可聚焦、仍是导航起点。
toneTone该条命令自身动作的性质:删除写 danger、停用写 warning。不写即与其余条目同档。 只换字色与悬停 / 按下的面,不改字重与缩进,也不表达选中或校验;禁用压过它。 红字不是唯一通道,破坏性命令仍要配图标。整张菜单的 tone 不下发给条目。
iconIconRecord图标,写入 item-icon 部件,排在条目文字之前;未提供时本条不铺该部件。 纯装饰:读屏从条目文字取意,不念它。勾选与单选条目的勾仍在 item-indicator,两者各占一格。
descriptionstring副文本,写入 item-description 部件;未提供时本条不铺该部件。
shortcutstring快捷键提示,写入 item-shortcut 部件;未提供时本条不铺该部件。 纯装饰:读屏从条目文字取意,不念它;只为真正注册了的组合写提示。
keyshortcutsstring条目的 aria-keyshortcuts:读屏念的快捷键,写法照 ARIA(修饰键在前,如 Control+S、Meta+Shift+Z,几组用空格隔开), 未提供时不写。与 shortcut 各管各:shortcut 是看得见的提示、读屏不念,这一项只给读屏,两处说的应是同一组键。
groupstring归属分组的身份值;相邻同值的条目收进同一个 group 部件。未提供时本条直接落在 content 上。
groupLabelstring分组标题文字,取本组首个提供它的条目;本组无人提供时不铺 group-label。
separatorBeforeboolean本条之前绘制一条分隔线;写在首条上不产出分隔线。本条领头一个分组时,分隔线绘制在分组外。
closeOnSelectboolean激活后是否关闭菜单;普通命令默认 true,checkbox / radio 默认 false。
childrenMenuNode[]子菜单的条目:给了 children 这一条就是子菜单的入口,Vue / React 的默认树按 children 递归铺出下一层, 深度不限;本条只能是普通条目(kind 为 item)。子层的选中经菜单树汇到根上,勾选与单选由各层自持。 手写部件时改用 Sub 部件;Web Components 由作者写 Light DOM,不读这一项。
checkboxValuestring[]子菜单那一层的勾选值:只在带 children 的条目上读取,交给按数据铺出的那一层,与子菜单自己的 checkboxValue 同义, 写了即受控。按数据铺时子层的勾选改动不另外上报,勾选条目写 closeOnSelect,由根上的 item-select 得知。
radioValueMenuRadioValue子菜单那一层的单选值(组 → 选中的值):只在带 children 的条目上读取,其余同 checkboxValue。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
open-changeMenuOpenChangeDetailsopen 状态变化;detail 为 { open: boolean }
item-selectMenuItemSelectDetails条目被选中(菜单随之关闭);detail 为 { value: string }
checkbox-value-changeMenuCheckboxValueChangeDetailscheckbox 选中集合变化;detail 为 { value: string[] }
radio-value-changeMenuRadioValueChangeDetailsRadioGroup 选中映射变化;detail 为 { value: Record&lt;string, string&gt; }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhMenuRootdefaultMenuRootSlotProps
XhMenuRoottrigger—
XhMenuRootitemMenuNodeMeta整条的接管口:写了它,代铺的各格一概不铺,作者自己放置部件
XhMenuRootitem-prefixMenuNodeMeta只接管行首那一格,其余槽照旧由数据铺
XhMenuRootitem-suffixMenuNodeMeta只接管行尾那一格(计数、徽标、次级图标),其余槽照旧由数据铺
XhMenuSubdefaultMenuSubSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhMenuGroupvaluestring是
XhMenuItemvaluestring是
XhMenuItemdisabledboolean默认交给 connect 查询 collection,写死 false 会覆盖数据中的禁用。
XhMenuPositionercontainer() => Element | null浮层挂载的容器;未提供时按全局配置,再未提供时挂载到 body。
XhMenuRadioGroupvaluestring是
XhMenuRoottriggerReactNode触发器中放置的内容;只提供 collection 时由它承载。
XhMenuRoottriggerAsChildboolean只提供 collection 时,trigger 给出的节点直接作为触发器使用,不再外包一个 button。
XhMenuRootlabelstring按数据铺设时触发按钮的文字;给了 trigger 时以它为准。
XhMenuRootrenderItem(node: MenuNodeMeta) => ReactNode每个条目的自定义内容;未提供时使用 collection 中的 label。
XhMenuRootrenderItemPrefix(node: MenuNodeMeta) => ReactNode只接管条目行首那一格;其余槽仍由数据铺。
XhMenuRootrenderItemSuffix(node: MenuNodeMeta) => ReactNode只接管条目行尾那一格(计数、徽标、次级图标);其余槽仍由数据铺。
XhMenuRootchildrenSlotChildren<MenuRootSlotProps>
XhMenuSubvaluestring是它在父菜单中的条目身份。
XhMenuSublabelstring按数据铺设时触发条目的文字;缺省取父菜单 collection 里这一条的 label。
XhMenuSubiconIconRecord按数据铺设时触发条目的图标;缺省取父菜单 collection 里这一条的 icon。
XhMenuSubdisabledboolean
XhMenuSubcollectionMenuNode[]
XhMenuSubcheckboxValuestring[]
XhMenuSubdefaultCheckboxValuestring[]
XhMenuSubradioValueMenuRadioValue
XhMenuSubdefaultRadioValueMenuRadioValue
XhMenuSubplacementPlacement
XhMenuSuboffsetnumber
XhMenuSubloopboolean
XhMenuSubopenOnHoverboolean
XhMenuSubhoverOpenDelaynumber
XhMenuSubhoverCloseDelaynumber
XhMenuSubdirDirection文字方向;默认继承父层。子层被迁移到浮层落点,无法继承父层的方向。
XhMenuSubtoneTone语气;默认继承父层。子层是浮层落点下的同级节点,CSS 私有槽无法继承。
XhMenuSubsizeSize尺寸;默认继承父层,理由同 tone。
XhMenuSubfitAvailableHeightboolean只按可用高度封顶;默认继承父层,理由同 tone。
XhMenuSubonCheckboxValueChangeMenuProps['onCheckboxValueChange']
XhMenuSubonRadioValueChangeMenuProps['onRadioValueChange']
XhMenuSubchildrenSlotChildren<MenuSubSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
trigger'open' | 'closed'
positioner'open' | 'closed'
content'open' | 'closed'
item-indicator'checked' | 'unchecked' | 'checked' | 'unchecked' | undefined
submenu-trigger'open' | 'closed'

以下名称仅用于内部状态机。

状态:open · closed

事件:OPEN · TOGGLE · CLOSE · PRESS.START · PRESS.END · CHECKBOX.VALUE.SET · RADIO.VALUE.SET · CONTROLLED.OPEN · CONTROLLED.CLOSE · ITEM.FOCUS · FOCUS.CLEAR · ITEM.LOST · ITEM.SELECT

判据:isOpenControlled · canPress · keepsMenuOpen

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
openboolean
disabledboolean整张菜单是否禁用。
collectionreadonly MenuNodeMeta[]由 collection 推导的条目元信息,按数据顺序排列;未提供 collection 时为空数组。
focusedValuestring | null焦点锚点;收起时为 null。
checkboxValuereadonly string[]
radioValueReadonly<MenuRadioValue>
isCheckboxItemChecked(value: string) => boolean
isRadioItemChecked(group: string, value: string) => boolean
setCheckboxValue(next: string[]) => void
setRadioValue(next: MenuRadioValue) => void
setOpen(next: boolean) => void
getTriggerProps() => T['button']
getPositionerProps() => T['element']
getContentProps() => T['element']
getItemProps(props: MenuItemProps) => T['element']
getCheckboxItemProps(props: MenuCheckboxItemProps) => T['element']
getRadioItemProps(props: MenuRadioItemProps) => T['element']
getItemIconProps(props: MenuAnyItemProps) => T['element']条目文字之前的图标格;装饰态,读屏不念。
getItemTextProps(props: MenuAnyItemProps) => T['element']
getItemIndicatorProps(props: MenuAnyItemProps) => T['element']
getItemDescriptionProps(props: MenuAnyItemProps) => T['element']
getItemShortcutProps(props: MenuAnyItemProps) => T['element']
getItemSuffixProps(props: MenuAnyItemProps) => T['element']
getSubmenuTriggerProps(props: MenuItemProps) => T['element']子菜单触发条目(submenu 模式):既是父菜单中的一条 item(value 是它在父菜单 中的身份,父层的方向键与高亮照常识别它),又是本子菜单的触发器(aria-haspopup、 悬停 / 点击 / 右方向键展开)。父层的选中会跳过带 aria-haspopup 的条目。
getSeparatorProps() => T['element']
getGroupProps(props: MenuGroupProps) => T['element']
getRadioGroupProps(props: MenuGroupProps) => T['element']
getGroupLabelProps(props: MenuGroupProps) => T['element']
getArrowProps() => T['element']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Space / ArrowDownfocus in trigger展开菜单并把焦点落到首个可用条目
ArrowUpfocus in trigger展开菜单并把焦点落到末个可用条目
ArrowDownopen, focus in content焦点移到下一个条目(禁用项跳过、尽头按 loop 回绕)
ArrowUpopen, focus in content焦点移到上一个条目(禁用项跳过、尽头按 loop 回绕)
Homeopen, focus in content焦点移到首个可用条目
Endopen, focus in content焦点移到末个可用条目
Enter / Spacefocus in item, not disabled派发选中详情并关闭菜单,焦点归还 trigger
Enter / Spaceheld in item, not disabled按住期间该条目投影 data-pressed,与指针 :active 同一副按压面;抬起、失焦或菜单收起撤下
Escapeopen关闭菜单并把焦点归还 trigger
Tab / Shift+Tabopen关闭菜单,焦点不归还 trigger,按 Tab 序列自然离开

ARIA ​

以下属性由 connect 生成。

部件属性值
triggeraria-controlscontent 部件的 id
triggeraria-expanded'true' | 'false'
triggeraria-haspopup'menu'
triggeraria-labelprops.translations.trigger
contentaria-hidden!open || undefined
contentaria-labelprops.translations.content
contentaria-labelledbytrigger 部件的 id | undefined
contentrole'menu'
item-iconaria-hidden'true'
item-shortcutaria-hidden'true'
item-indicatoraria-hidden'true'
separatoraria-orientation'horizontal'
separatorrole'separator'
grouparia-labelledbygroup-label 部件的 id
grouprole'group'
arrowaria-hidden'true'
submenu-triggeraria-controlscontent 部件的 id
submenu-triggeraria-disabled'true' | 'false'
submenu-triggeraria-expanded'true' | 'false'
submenu-triggeraria-haspopup'menu'
radio-grouparia-labelledbygroup-label 部件的 id
submenu-triggerrole'menuitem'
radio-grouprole'group'

样式参考 ​

皮肤 ​

@xihan-ui/styles/menu.css 按 [data-scope="menu"][data-part="trigger"] 部件选择器书写,发布产物以挂载类 .xh-scope-menu 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
triggerdata-disabled''(条件成立时才出现)
triggerdata-state'open' | 'closed'
positionerdata-hidden''(条件成立时才出现)
positionerdata-placement定位引擎算出的实际落位
positionerdata-positioned''(条件成立时才出现)
positionerdata-state'open' | 'closed'
contentdata-fit-available-height''(条件成立时才出现)
contentdata-instant''(条件成立时才出现)
contentdata-placement定位引擎算出的实际落位
contentdata-sizeprops.size
contentdata-state'open' | 'closed'
contentdata-toneprops.tone
contentdata-xh-material'frosted'
itemdata-xh-collection-context'overlay'
itemdata-xh-collection-item''
item-icondata-disabled''(条件成立时才出现)
item-icondata-highlighted''(条件成立时才出现)
item-icondata-xh-collection-slot'icon'
item-textdata-disabled''(条件成立时才出现)
item-textdata-highlighted''(条件成立时才出现)
item-textdata-xh-collection-slot'text'
item-descriptiondata-disabled''(条件成立时才出现)
item-descriptiondata-highlighted''(条件成立时才出现)
item-descriptiondata-xh-collection-slot'description'
item-shortcutdata-disabled''(条件成立时才出现)
item-shortcutdata-highlighted''(条件成立时才出现)
item-shortcutdata-xh-collection-slot'shortcut'
item-suffixdata-disabled''(条件成立时才出现)
item-suffixdata-highlighted''(条件成立时才出现)
item-suffixdata-xh-collection-slot'suffix'
item-indicatordata-disabled''(条件成立时才出现)
item-indicatordata-highlighted''(条件成立时才出现)
item-indicatordata-state'checked' | 'unchecked' | 'checked' | 'unchecked' | undefined
item-indicatordata-xh-collection-slot'indicator'
item-indicatordata-xh-menu-choice-indicatoritem.kind | undefined
separatordata-xh-collection-separator''
arrowdata-placement定位引擎算出的实际落位
submenu-triggerdata-disabled''(条件成立时才出现)
submenu-triggerdata-in-path''(条件成立时才出现)
submenu-triggerdata-pressed''(条件成立时才出现)
submenu-triggerdata-state'open' | 'closed'
radio-groupdata-valuegroup.value
submenu-triggerdata-xh-collection-context'overlay'
submenu-triggerdata-xh-collection-item''
submenu-triggerdata-xh-collection-sizeprops.size

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-menu-arrow-sizearrow--xh-_overlay-arrow-sizedefault--xh-overlay-arrow-sizemenu 的 arrow 部件 --xh-_overlay-arrow-size 覆盖槽。
--xh-menu-backdropcontent-webkit-backdrop-filter
backdrop-filter
xh-material=frosted--xh-_material-backdropmenu 的 content 部件 -webkit-backdrop-filter、backdrop-filter 覆盖槽。
--xh-menu-borderarrow
content
borderdefault
not([data-xh-action-control])
xh-material=frosted
--xh-_material-border
--xh-material-frosted-border
menu 的 arrow、content 部件 border 覆盖槽。
--xh-menu-content-bgarrow
content
backgrounddefault
not([data-xh-action-control])
xh-material=frosted
--xh-_material-bg
--xh-material-frosted-bg
menu 的 arrow、content 部件 background 覆盖槽。
--xh-menu-content-fgcontentcolornot([data-xh-action-control])
xh-material=frosted
--xh-_material-fgmenu 的 content 部件 color 覆盖槽。
--xh-menu-content-gapcontentgapdefault--xh-list-option-gapmenu 的 content 部件 gap 覆盖槽。
--xh-menu-content-pxcontentpadding-inlinedefault--xh-space-1menu 的 content 部件 padding-inline 覆盖槽。
--xh-menu-content-pycontentpadding-blockdefault--xh-surface-pad-xsmenu 的 content 部件 padding-block 覆盖槽。
--xh-menu-content-radiuscontentborder-radiusdefault--xh-shape-overlaymenu 的 content 部件 border-radius 覆盖槽。
--xh-menu-content-shadowcontentbox-shadownot([data-xh-action-control])
xh-material=frosted
--xh-_material-shadowmenu 的 content 部件 box-shadow 覆盖槽。
--xh-menu-group-gapgroupgapdefault--xh-list-option-gapmenu 的 group 部件 gap 覆盖槽。
--xh-menu-group-label-fggroup-labelcolordefault--xh-material-frosted-fg-mutedmenu 的 group-label 部件 color 覆盖槽。
--xh-menu-group-label-font-sizegroup-labelfont-sizedefault--xh-text-caption-sizemenu 的 group-label 部件 font-size 覆盖槽。
--xh-menu-group-label-font-weightgroup-labelfont-weightdefault--xh-font-weight-regularmenu 的 group-label 部件 font-weight 覆盖槽。
--xh-menu-group-label-mtgroup-labelmargin-block-startdefault--xh-space-2menu 的 group-label 部件 margin-block-start 覆盖槽。
--xh-menu-group-label-pxgroup-labelpadding-inlinedefault--xh-_menu-item-pxmenu 的 group-label 部件 padding-inline 覆盖槽。
--xh-menu-group-label-pygroup-labelpadding-blockdefault--xh-space-1menu 的 group-label 部件 padding-block 覆盖槽。
--xh-menu-highlightcontentbackgroundnot([data-xh-action-control])
xh-material=frosted
--xh-_material-highlightmenu 的 content 部件 background 覆盖槽。
--xh-menu-icon-sizecontent--xh-icon-sizedefault
size=lg
size=sm
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
menu 的 content 部件 --xh-icon-size 覆盖槽。
--xh-menu-item-bg-activeitembackground-colorin-path--xh-bg-subtlemenu 的 item 部件 background-color 覆盖槽。
--xh-menu-item-bg-hoveritembackground-colordisabled
error
highlighted
hover
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
--xh-bg-subtlemenu 的 item 部件 background-color 覆盖槽。
--xh-menu-item-bg-presseditembackground-colordisabled
error
is(:active, [data-pressed])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
--xh-bg-subtle-hovermenu 的 item 部件 background-color 覆盖槽。
--xh-menu-item-description-fgitem-descriptioncolordefault--xh-material-frosted-fg-mutedmenu 的 item-description 部件 color 覆盖槽。
--xh-menu-item-description-font-sizeitem-descriptionfont-sizedefault--xh-control-caption-mdmenu 的 item-description 部件 font-size 覆盖槽。
--xh-menu-item-fgitemcolordefault
disabled
error
highlighted
hover
in-path
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
--xh-material-frosted-fgmenu 的 item 部件 color 覆盖槽。
--xh-menu-item-font-sizeitemfont-sizedefault--xh-_menu-font-sizemenu 的 item 部件 font-size 覆盖槽。
--xh-menu-item-gapitemgapdefault--xh-_menu-item-gapmenu 的 item 部件 gap 覆盖槽。
--xh-menu-item-hitemmin-block-sizedefault--xh-_menu-item-hmenu 的 item 部件 min-block-size 覆盖槽。
--xh-menu-item-indicator-fgitem-indicatorcolordefault--xh-_tonemenu 的 item-indicator 部件 color 覆盖槽。
--xh-menu-item-indicator-sizecontent
group
item
item-indicator
--xh-icon-size
block-size
inline-size
default
has(> [data-scope='menu'][data-part='item'] > [data-xh-menu-choice-indicator], > [data-scope='menu'][data-part='group'] > [data-scope='menu'][data-part='item'] > [data-xh-menu-choice-indicator])
not([aria-haspopup='menu'], [aria-checked])
xh-menu-choice-indicator
--xh-control-indicator-sizemenu 的 content、group、item、item-indicator 部件 --xh-icon-size、block-size、inline-size 覆盖槽。
--xh-menu-item-leadingitemline-heightdefault--xh-leading-normalmenu 的 item 部件 line-height 覆盖槽。
--xh-menu-item-pxitempadding-inlinedefault--xh-_menu-item-pxmenu 的 item 部件 padding-inline 覆盖槽。
--xh-menu-item-pyitempadding-blockdefault--xh-_menu-item-pymenu 的 item 部件 padding-block 覆盖槽。
--xh-menu-item-radiusitemborder-radiusdefault--xh-shape-insetmenu 的 item 部件 border-radius 覆盖槽。
--xh-menu-layerpositionerz-indexdefault--xh-_layermenu 的 positioner 部件 z-index 覆盖槽。
--xh-menu-max-hcontentmax-block-sizedefault--xh-_menu-max-hmenu 的 content 部件 max-block-size 覆盖槽。
--xh-menu-max-wcontentmax-inline-sizedefault--xh-overlay-max-wmenu 的 content 部件 max-inline-size 覆盖槽。
--xh-menu-min-wcontentmin-inline-sizedefault--xh-overlay-menu-min-wmenu 的 content 部件 min-inline-size 覆盖槽。
--xh-menu-separator-colorseparatorbackgrounddefault--xh-material-frosted-separatormenu 的 separator 部件 background 覆盖槽。
--xh-menu-separator-myseparatormargin-blockdefault--xh-space-0_5menu 的 separator 部件 margin-block 覆盖槽。
--xh-menu-separator-radiusseparatorborder-radiusdefault--xh-shape-pillmenu 的 separator 部件 border-radius 覆盖槽。
--xh-menu-separator-thicknessseparatorblock-sizedefault--xh-stroke-thinmenu 的 separator 部件 block-size 覆盖槽。
--xh-menu-submenu-indicator-fgitembackground-colordefaultcurrentColormenu 的 item 部件 background-color 覆盖槽。
--xh-menu-submenu-indicator-sizeitemblock-size
inline-size
default--xh-control-indicator-sizemenu 的 item 部件 block-size、inline-size 覆盖槽。
--xh-menu-trigger-bg-activetriggerbackgrounddisabled
not([data-disabled])
state=open
--xh-bg-subtlemenu 的 trigger 部件 background 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 出现(见动效规范)。

共享关键帧 xh-overlay-pop-in · xh-pop-out 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立。时长与缓动读动效令牌,改令牌即改全局节奏。

皮肤之外还有一段:退场由适配器的退场闸门把关,动画播完才真收起。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License