Button 按钮
用于触发即时操作。
用法
触发一次操作
组件结构
加粗的是必需部件。
data-scope="button":root · label · indicator · prefix · suffix
示例
变体
设置按钮外观
尺寸
小、中、大三档
图标
在文字前后放置图标
仅图标
紧凑的图标操作
加载
保留按钮标签并阻止重复操作
异步操作
点击后显示加载状态
全宽
占满容器宽度
禁用
暂时不可执行的操作
链接
保留原生导航能力
设计指引
何时使用
- 提交表单或执行命令。
- 打开菜单、对话框等浮层。
- 需要明确主次关系的一组操作。
何时不用
特性
- 支持四种变体、六种颜色和三种尺寸。
- 缺省变体是品牌实心
solid,这是按钮独有的缺省;其余触发器缺省中性。 - 支持文字、图标、图标加文字与全宽按钮。
loading保留焦点并阻止重复操作。as="a"保留原生链接能力。- 应用设为
data-material="liquid"时,实心按钮在细指针悬停的一刻有一道光沿描边扫过一次;光只走描边、不进面,文字对比不受影响。粗指针、减弱动效与强制色下不播。
组合
- 使用
prefix与suffix放置图标。 - 使用
indicator提供加载图形。 - 使用按钮组组合相关操作。
最佳实践
- 每个视图只保留一个主要操作。
- 图标按钮必须提供
aria-label。 - 加载时保留原有标签,避免按钮宽度变化。
反模式
- 不要使用按钮模拟普通链接。
- 不要在按钮中嵌套可聚焦元素。
API 参考
产物
| 层 | 值 |
|---|---|
| 自定义元素 | <xh-button> |
| Vue 组件 | XhButton XhButtonIndicator XhButtonLabel XhButtonPrefix XhButtonSuffix |
| 状态机 | buttonMachine |
| 皮肤 | @xihan-ui/styles/button.css |
Props
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | 'button' | 'submit' | 'reset' | ||
disabled | boolean | ||
loading | boolean | 加载态:用 aria-disabled + 拦截事件表达,保留焦点。 | |
variant | ActionVariant | 变体:solid / subtle / outline / ghost,默认 solid——只有 Button 缺省品牌实心,其余触发器缺省中性。 | |
tone | Tone | 颜色:brand / neutral / success / warning / danger / info。 | |
size | Size | ||
iconOnly | boolean | 仅图标:左右内边距清零、宽高相等。宽度跟随当前尺寸档的高度, 不必把档位写进行内样式。图标按钮没有可见文字,作者须自行提供可及名。 | |
ariaLabel | string | 作者写在根节点上的可及名(aria-label / aria-labelledby)。 宿主只把它们转告连接层,用于判断图标按钮是否有名字;属性本身仍由宿主写入根节点。 | |
ariaLabelledby | string | ||
fullWidth | boolean | 撑满行宽:表单末尾的提交按钮与移动端常用。 | |
as | ButtonElement | 渲染的标签,默认 button。 写为 a 时不再产出 type 与原生 disabled(两者在链接上无效),禁用改由 aria-disabled 表达, 点击仍被拦截。href 由作者自行提供。 |
React 适配器 props
只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。
| React 组件 | 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
XhButton | href | ComponentPropsWithRef<'a'>['href'] | ||
XhButton | target | ComponentPropsWithRef<'a'>['target'] | ||
XhButton | rel | ComponentPropsWithRef<'a'>['rel'] |
状态
以下名称仅用于内部状态机。
状态:idle
事件:PRESS.START · PRESS.END
判据:canPress
connect API
getXxxProps() 返回对应部件的宿主属性。
| 成员 | 类型 | 说明 |
|---|---|---|
disabled | boolean | |
loading | boolean | |
getRootProps | () => T['button'] | |
getLabelProps | () => T['element'] | |
getIndicatorProps | () => T['element'] | |
getPrefixProps | () => T['element'] | |
getSuffixProps | () => T['element'] |
无障碍
键盘
规格出处:W3C APG
| 按键 | 生效条件 | 行为 |
|---|---|---|
Enter / Space | focus in root, interactive | 激活按钮(原生行为) |
Enter / Space | held in root, interactive | 按住期间投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下 |
ARIA
以下属性由 connect 生成。
| 部件 | 属性 | 值 |
|---|---|---|
root | aria-busy | 'true' | undefined |
root | aria-disabled | 'true' | undefined |
indicator | aria-hidden | 'true' |
prefix | aria-hidden | 'true' |
suffix | aria-hidden | 'true' |
样式参考
皮肤
@xihan-ui/styles/button.css 使用 [data-scope="button"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。
forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。
数据属性
由 connect 生成;条件不成立时不输出无值属性。
| 部件 | 属性 | 值 |
|---|---|---|
root | data-disabled | ''(条件成立时才出现) |
root | data-full-width | ''(条件成立时才出现) |
root | data-icon-only | ''(条件成立时才出现) |
root | data-loading | ''(条件成立时才出现) |
root | data-pressed | ''(条件成立时才出现) |
root | data-size | props.size |
root | data-tone | props.tone |
root | data-variant | props.variant |
root | data-xh-action-control | '' |
root | data-xh-action-display | 'always' |
root | data-xh-action-profile | 'icon' | 'text' |
root | data-xh-action-size | props.size |
root | data-xh-action-variant | props.variant |
root | data-xh-ink-surface | ''(条件成立时才出现) |
CSS 变量
本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。
| 变量 | 部件 | CSS 属性 | 状态 | 默认来源 | 说明 |
|---|---|---|---|---|---|
--xh-button-bg | root | --xh-ink-surfacebackground-color | defaultfocus-visibleloadingxh-ink-surface | --xh-_action-variant-bg-focus-visible--xh-_action-variant-bg-loading--xh-_action-variant-bg-rest | button 的 root 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-button-bg-active | root | background-color | disabledis(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_action-variant-bg-pressed | button 的 root 部件 background-color 覆盖槽。 |
--xh-button-bg-hover | root | background-color | disabledhoverloadingnot([data-disabled])not([data-loading]) | --xh-_action-variant-bg-hover | button 的 root 部件 background-color 覆盖槽。 |
--xh-button-fg | root | color | defaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_action-variant-fg-focus-visible--xh-_action-variant-fg-hover--xh-_action-variant-fg-loading--xh-_action-variant-fg-pressed--xh-_action-variant-fg-rest | button 的 root 部件 color 覆盖槽。 |
--xh-button-font-size | root | font-size | default | --xh-_button-group-font-size | button 的 root 部件 font-size 覆盖槽。 |
--xh-button-font-weight | root | font-weight | default | --xh-text-label-weight | button 的 root 部件 font-weight 覆盖槽。 |
--xh-button-gap | root | gap | default | --xh-_button-group-gap | button 的 root 部件 gap 覆盖槽。 |
--xh-button-glint-duration | root | animation | @media (hover: hover) and (pointer: fine) and (forced-colors: none)disabledhoverloadingmaterial=liquidnot([data-disabled])not([data-loading])where([data-material='liquid'])xh-action-variant=solid | --xh-motion-duration-glint | button 的 root 部件 animation 覆盖槽。 |
--xh-button-h | root | block-sizeinline-size | defaultxh-action-profile=icon | --xh-_button-group-h | button 的 root 部件 block-size、inline-size 覆盖槽。 |
--xh-button-icon-size | root | --xh-icon-size | default | --xh-_action-profile-glyph-size | button 的 root 部件 --xh-icon-size 覆盖槽。 |
--xh-button-px | root | padding-inline | default | --xh-_button-group-px | button 的 root 部件 padding-inline 覆盖槽。 |
--xh-button-radius | root | border-radius | default | --xh-_button-radius | button 的 root 部件 border-radius 覆盖槽。 |
--xh-button-shadow | root | box-shadow | default | none | button 的 root 部件 box-shadow 覆盖槽。 |
--xh-button-shadow-hover | root | box-shadow | disabledhoverloadingnot([data-disabled])not([data-loading]) | none | button 的 root 部件 box-shadow 覆盖槽。 |
--xh-button-spin-duration | indicatorroot | animation | loading | --xh-motion-loop-spin | button 的 indicator、root 部件 animation 覆盖槽。 |
动效
动效角色:按压 · 状态 · 循环(见动效规范)。
可覆盖的动效槽:--xh-button-glint-duration · --xh-button-spin-duration。
共享关键帧 xh-spin 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立。时长与缓动读动效令牌,改令牌即改全局节奏。
prefers-reduced-motion: reduce 下本组件另有降级规则。
响应式
皮肤另按输入能力分档:hover: hover:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。
RTL
皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。
