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

查看生态总览
跳转到内容

Toolbar 工具栏 ​

用于组织一组相关的操作控件。

用法 ​

集中常用编辑操作

组件结构 ​

加粗的是必需部件。

data-scope="toolbar":root · group · item · separator · overflow-trigger

示例 ​

分组 ​

将相关操作收在一起

垂直布局 ​

按纵向排列工具

附着工具面 ​

为悬浮工具条提供完整表面

收进更多菜单 ​

放不下的操作按次序收进行尾的更多按钮

设计指引 ​

何时使用 ​

  • 文本编辑、表格操作或画布工具。
  • 相关控件需要统一的方向键导航。

何时不用 ​

  • 只有少量独立操作时直接使用按钮。
  • 操作必须连接成一个整体时使用按钮组。

特性 ​

  • 默认 ghost 形态只组织控件,不绘制工具条外框。
  • outline 形态提供带内距、描边与背景的附着式工具面;subtle 为淡底。
  • group 将相关操作连接成连续分段,并以低对比度分隔线区分。
  • 独立条目是接入 Action Control text 档的无描边工具按钮,组内条目使用中性操作面;aria-pressed 表示选中状态,选中项是实心主色配面上反白(与 Toggle、切换按钮组的选中段同一块面),悬停与按压走主色的深一档、再深一档。
  • 条目只放图标时声明 iconOnly(Web Components 在条目上写 data-icon-only):条目按方钮画,宽等于高,三种尺寸都一样。
  • 支持水平、垂直、分组、分隔线与整体禁用。
  • 方向键在条目间移动,禁用项会被跳过。
  • 放了 overflow-trigger 时不折行:宽度不够时,放不下的条目按次序收进行尾的「更多」按钮,点开是一张菜单,选中其中一项即触发该条目自己的点击;宽度够时「更多」按钮收起。容器变宽变窄、条目增减或改写后自动重新计算。

组合 ​

  • 使用 group 收紧相关操作。
  • 使用 separator 区分操作组。
  • 使用 overflow-trigger 放在 root 的最后,承接放不下的条目。菜单里的文字取条目的 aria-label(没有时取条目文字),写了 aria-pressed 的开关条目在菜单里显示为勾选项,条目上写的 data-tone(如破坏性操作的 danger)随条目带进菜单项,工具条上的分组与分隔线在菜单里画成分隔线。itemIcons 按条目的 value 给图标记录,收起的条目带着它进菜单,排在文字之前;工具条上那颗按钮里放不放图标归作者。不写内容时由皮肤画一枚横排三点,可及名缺省为 More,用 translations.overflowTrigger 换成本地文案。
  • Web Components 只写一颗空的 <button data-xh-part="overflow-trigger">,菜单的浮层与条目由元素自己建。

最佳实践 ​

  • 仅图标条目声明 iconOnly,并且必须提供 aria-label:它也是条目收进菜单后显示的文字。
  • 使用 aria-pressed 表示可切换工具的当前状态。
  • 常用的操作排在前面:收纳从尾部开始,排在最后的最先收进菜单。

反模式 ​

  • 不要在工具栏中放置文本输入控件。
  • 不要将整页所有操作放入同一工具栏。
  • 不要在放不下时让工具条横向滚动:用 overflow-trigger 收进菜单。

API 参考 ​

产物 ​

层值
自定义元素<xh-toolbar>
Vue 组件XhToolbarGroup XhToolbarItem XhToolbarOverflowTrigger XhToolbarRoot XhToolbarSeparator
组合式函数useToolbar
状态机toolbarMachine
皮肤@xihan-ui/styles/toolbar.css

Props ​

属性类型必填说明
orientationOrientation主轴,默认 horizontal。它决定 root 的 aria-orientation、方向键接管哪一对键 (另一轴原样放行给页面),以及分隔线的朝向(恒与主轴垂直)。
dirDirection文字方向,默认 ltr;只改写水平主轴上左右方向键的语义。
loopboolean方向键到达末尾是否回绕,默认 true。
disabledboolean整条禁用:条目全部为 aria-disabled,方向键不再接管。
variantControlVariant形态:ghost 只组织控件不画面(默认),outline 为附着式工具面,subtle 为淡底。默认 ghost。
sizeSize尺寸:sm / md / lg,同时调整排布与默认条目尺寸。
translationsPartial<ToolbarTranslations>读屏文案:「更多」钮的可及名,缺省 More。
itemIconsReadonly<Record<string, IconRecord>>条目的图标,键是条目的 value:收起进「更多」菜单的条目带着它,排在文字之前。条目自己(工具条上的那颗按钮)里放不放图标归作者。

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhToolbarRootdefaultToolbarRootSlotProps

React 适配器 props ​

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

React 组件属性类型必填说明
XhToolbarItemvaluestring是
XhToolbarItemdisabledboolean
XhToolbarItemiconOnlyboolean只放图标、没有看得见的文字:按方钮画,宽等于高;名字由 aria-label 给。
XhToolbarItemasElementType条目渲染为哪个标签,默认 button;不自动补 type="button",表单内需自行声明。
XhToolbarRootchildrenSlotChildren<ToolbarRootSlotProps>

状态 ​

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

状态:idle

事件:ITEM.FOCUS · OVERFLOW_TRIGGER.FOCUS · TOOLBAR.BLUR · PRESS.START · PRESS.END · OVERFLOW.SELECT

判据:canPress

connect API ​

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

成员类型说明
focusedValuestring | null焦点锚点;焦点不在工具条内、或停在「更多」钮上时为 null。
orientationOrientation生效的主轴。
separatorOrientationOrientation分隔线的朝向:恒与主轴垂直(横向工具条中的分隔线是竖线)。
disabledboolean
overflowItemsreadonly ToolbarOverflowItem[]收进「更多」菜单的条目,文档序;全部放得下时为空数组。
getRootProps() => T['element']
getGroupProps() => T['element']
getItemProps(props: ToolbarItemProps) => T['element']
getSeparatorProps() => T['element']
getOverflowTriggerProps() => T['button']行尾的「更多」钮,也是「更多」菜单的触发器:适配器按 asChild 的规则把菜单的开合接线合进来,解剖标记归工具条,工具条的处理器先跑。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Tab / Shift+Tabroving tabindex(恒开)整条只占一个 Tab 位:焦点落到锚点条目,无锚点时先落容器再由它转投给第一个可停留条目
ArrowRight / ArrowDown焦点在条内且未整条禁用;横排收 ArrowRight、竖排收 ArrowDown焦点移到下一个可停留条目(禁用项与收进菜单的条目跳过、放不下时「更多」钮排在最后、尽头按 loop 回绕);dir=rtl 时水平主轴改由 ArrowLeft 承担
ArrowLeft / ArrowUp焦点在条内且未整条禁用;横排收 ArrowLeft、竖排收 ArrowUp焦点移到上一个可停留条目(禁用项与收进菜单的条目跳过、尽头按 loop 回绕);dir=rtl 时水平主轴改由 ArrowRight 承担
Home焦点在条内且未整条禁用焦点移到首个可停留条目
End焦点在条内且未整条禁用焦点移到末个可停留条目;放不下时是「更多」钮
Enter / Spaceheld on item, 整条未禁用且条目未禁用按住期间该条目投影 data-pressed,与指针 :active 同一副按压面;抬起、失焦或转禁用撤下。激活语义仍归条目自身(原生 button 的 click)
Enter / Space / ArrowDown / ArrowUp焦点在「更多」钮上;竖排工具条里上下键仍归工具条走位,只收 Enter 与 Space展开「更多」菜单:Enter / Space / ArrowDown 落到首项,ArrowUp 落到末项;菜单里选中一项即替收起的条目触发它自己的点击,菜单收起
Escape「更多」菜单展开收起菜单,焦点回到「更多」钮
交叉轴的两个方向键焦点在条内(横排按上下、竖排按左右)不归工具条管:原样放行给页面滚动与读屏,绝不 preventDefault;落在菜单触发器(含「更多」钮)上时由触发器展开菜单

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-disabled'true' | 'false'
rootaria-orientationprops.orientation
rootrole'toolbar'
grouprole'group'
itemaria-disabled'true' | 'false'
separatoraria-orientation'vertical' | 'horizontal'
separatorrole'separator'
overflow-triggeraria-disabled'true' | 'false'
overflow-triggeraria-labelresolveTranslations(TOOLBAR_EN_US, prop('translations…

样式参考 ​

皮肤 ​

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

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

数据属性 ​

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

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-orientationprops.orientation
rootdata-sizeprops.size
rootdata-variantprops.variant
groupdata-disabled''(条件成立时才出现)
groupdata-orientationprops.orientation
itemdata-disabled''(条件成立时才出现)
itemdata-icon-only''(条件成立时才出现)
itemdata-pressed''(条件成立时才出现)
itemdata-xh-action-control''
itemdata-xh-action-display'always'
itemdata-xh-action-profile'icon' | 'text'
itemdata-xh-action-sizeprops.size
itemdata-xh-action-variant'ghost'
separatordata-orientation'vertical' | 'horizontal'
overflow-triggerdata-disabled''(条件成立时才出现)
overflow-triggerdata-xh-action-control''
overflow-triggerdata-xh-action-display'always'
overflow-triggerdata-xh-action-profile'icon'
overflow-triggerdata-xh-action-sizeprops.size
overflow-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

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

变量部件CSS 属性状态默认来源说明
--xh-toolbar-bgrootbackgrounddefault--xh-_toolbar-root-bgtoolbar 的 root 部件 background 覆盖槽。
--xh-toolbar-bg-disabledrootbackgrounddisabled--xh-_toolbar-root-bg-disabledtoolbar 的 root 部件 background 覆盖槽。
--xh-toolbar-borderrootborderdefault--xh-_toolbar-root-bordertoolbar 的 root 部件 border 覆盖槽。
--xh-toolbar-fgrootcolordefault--xh-fg-defaulttoolbar 的 root 部件 color 覆盖槽。
--xh-toolbar-gaprootgapdefault--xh-_toolbar-gaptoolbar 的 root 部件 gap 覆盖槽。
--xh-toolbar-group-gapgroupgapdefault--xh-space-0toolbar 的 group 部件 gap 覆盖槽。
--xh-toolbar-icon-sizeroot--xh-icon-sizedefault
size=lg
size=sm
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
toolbar 的 root 部件 --xh-icon-size 覆盖槽。
--xh-toolbar-item-bggroup
item
--xh-ink-surface
background-color
default
not([aria-pressed='true'])
xh-ink-surface
--xh-_action-variant-bg-rest
--xh-bg-subtle
toolbar 的 group、item 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-toolbar-item-bg-activeitembackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedtoolbar 的 item 部件 background-color 覆盖槽。
--xh-toolbar-item-bg-disabledgroup
item
--xh-ink-surface
background-color
disabled
not([aria-pressed='true'])
xh-ink-surface
--xh-_action-variant-bg-disabled
--xh-bg-subtle
toolbar 的 group、item 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-toolbar-item-bg-hoveritembackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertoolbar 的 item 部件 background-color 覆盖槽。
--xh-toolbar-item-bg-presseditem--xh-ink-surface
background-color
border
border-color
default
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
xh-ink-surface
--xh-bg-brandtoolbar 的 item 部件 --xh-ink-surface、background-color、border、border-color 覆盖槽。
--xh-toolbar-item-bg-pressed-activeitembackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-bg-brand-activetoolbar 的 item 部件 background-color 覆盖槽。
--xh-toolbar-item-bg-pressed-disableditem--xh-ink-surface
background-color
disabled
xh-ink-surface
--xh-toolbar-item-bg-pressedtoolbar 的 item 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-toolbar-item-bg-pressed-hoveritembackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-bg-brand-hovertoolbar 的 item 部件 background-color 覆盖槽。
--xh-toolbar-item-fgitemcolor@media print
default
disabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-fg-hover
--xh-_action-variant-fg-pressed
--xh-_action-variant-fg-rest
--xh-fg-default
toolbar 的 item 部件 color 覆盖槽。
--xh-toolbar-item-fg-presseditemcolordefault
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-on-brandtoolbar 的 item 部件 color 覆盖槽。
--xh-toolbar-item-font-sizeitemfont-sizedefault--xh-_action-profile-font-sizetoolbar 的 item 部件 font-size 覆盖槽。
--xh-toolbar-item-font-weightitemfont-weightdefault--xh-text-label-weighttoolbar 的 item 部件 font-weight 覆盖槽。
--xh-toolbar-item-gapitemgapdefault--xh-_action-profile-gaptoolbar 的 item 部件 gap 覆盖槽。
--xh-toolbar-item-hitemblock-size
inline-size
min-inline-size
default
icon-only
orientation=vertical
xh-action-profile=icon
--xh-_action-profile-visual-sizetoolbar 的 item 部件 block-size、inline-size、min-inline-size 覆盖槽。
--xh-toolbar-item-pxitempadding-inlinedefault--xh-_action-profile-padding-inlinetoolbar 的 item 部件 padding-inline 覆盖槽。
--xh-toolbar-item-radiusgroup
item
border-end-end-radius
border-end-start-radius
border-radius
border-start-end-radius
border-start-start-radius
default
first-of-type
last-of-type
not(:has(~ [data-scope='toolbar'][data-part='item']:not([hidden])
not([hidden])
orientation=horizontal
orientation=vertical
--xh-_action-profile-radius
--xh-shape-control
toolbar 的 group、item 部件 border-end-end-radius、border-end-start-radius、border-radius、border-start-end-radius、border-start-start-radius 覆盖槽。
--xh-toolbar-pxrootpadding-inlinedefault--xh-_toolbar-root-ptoolbar 的 root 部件 padding-inline 覆盖槽。
--xh-toolbar-pyrootpadding-blockdefault--xh-_toolbar-root-ptoolbar 的 root 部件 padding-block 覆盖槽。
--xh-toolbar-radiusrootborder-radiusdefault
variant=outline
--xh-shape-surfacetoolbar 的 root 部件 border-radius 覆盖槽。
--xh-toolbar-separator-colorgroup
separator
backgrounddefault--xh-border-default
--xh-fg-default
toolbar 的 group、separator 部件 background 覆盖槽。
--xh-toolbar-separator-gapseparatormargin-block
margin-inline
orientation=horizontal
orientation=vertical
--xh-space-3toolbar 的 separator 部件 margin-block、margin-inline 覆盖槽。
--xh-toolbar-separator-insetseparatormargin-block
margin-inline
orientation=horizontal
orientation=vertical
--xh-space-0toolbar 的 separator 部件 margin-block、margin-inline 覆盖槽。
--xh-toolbar-separator-opacitygroup
separator
opacitydefault--xh-control-separator-opacitytoolbar 的 group、separator 部件 opacity 覆盖槽。
--xh-toolbar-separator-radiusseparatorborder-radiusdefault--xh-shape-pilltoolbar 的 separator 部件 border-radius 覆盖槽。
--xh-toolbar-separator-thicknessgroup
separator
block-size
inline-size
margin-block
margin-inline
orientation=horizontal
orientation=vertical
--xh-stroke-thintoolbar 的 group、separator 部件 block-size、inline-size、margin-block、margin-inline 覆盖槽。
--xh-toolbar-shadowrootbox-shadowvariant=outlinenonetoolbar 的 root 部件 box-shadow 覆盖槽。

动效 ​

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

background-color · color 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

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

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

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License