动作
Button - 按钮
系统的动作,和它旁边那个输入框用同一个圆角。
用法
什么时候用它
import { Button } from '@misoto22/folio'说明
这套系统的动作。
渲染成 <button>;给了 href 就渲染成 <a>;用 asChild 时你给什么就渲染什么。这里不引入任何路由库,所以这个包对框架保持中立,Next 或 React Router 应用在调用处接上自己的 Link。
对服务端组件友好:这里没有客户端边界,所以它在静态页面里和在交互页面里一样能渲染。
结构
| 部件 | 说明 |
|---|---|
| 控件盒子必填 | 那个 <button>;给了 href 就是 <a>;用了 asChild 就是塞进来的那个元素。variant、size,以及和旁边输入框同一个 --radius 圆角,都长在它身上。 |
| 标签 | children,也是文字按钮的无障碍名称。loading 期间它留在原地,所以宽度不会在指针底下变。 |
| 图标 | iconOnly 按钮上还是 children 这个位置:盒子变成正方形,内边距归零,读屏软件那边不剩任何文字形状的东西。 |
| 快捷键帽 | keycap,跟在标签后面——一个带边框、降了透明度的等宽字符。它是真的文字,不是对辅助技术隐藏的装饰。 |
| 加载环 | loading 时出现在标签前面——一个按所处底色取色的 Spinner,并且传了 label={null},所以它是 aria-hidden 的,状态改由控件上的 aria-busy 承担。 |
实践建议
推荐
- 表单的提交控件要把 type="submit" 写出来:这里的默认值是 type="button",所以表单底部那个按钮看着没问题,但什么都不会提交。
- 一个视图里只留一个 primary。variant 默认就是 primary,所以一排按钮全都不写这个属性,就是一排都在宣称自己是这屏唯一该做的事。
- 用 loading,不要自己去换标签:它一步就把标签留住、设上 aria-busy 并禁用控件,盒子不会在刚点下去的指针底下塌掉。
- 会跳转就用 href,跳转由路由器接管就用 asChild——onClick 里调 router.push 的 <button> 没法在新标签页打开,读屏播报出来也是一个哪儿都不去的按钮。
避免
- asChild 只把样式交给子元素,别的什么都不给:keycap 和 loading 根本到不了那里,所以这样写出来的加载态既没有转圈,也拦不住点击。
- sm 在默认密度下是 36px,低于 md 自己就能达到的 44px——整条工具栏都用 sm,就是一排拇指点不中的目标(WCAG 2.5.5)。
- danger 是一种状态,不是强调。把它花在只是「重要」的动作上,等真有破坏性操作时,就没有任何东西还读得出破坏性了。
- 键帽没有对辅助技术隐藏,所以那个字符会并进无障碍名称——控件被念成「Save S」;而给一个根本没有绑定的快捷键做键帽,是在播报一个页面从不兑现的承诺。
示例
variants
四个 variant,按它们争夺注意力的顺序排开。variant 默认是 primary,所以一屏只留一个,其余控件一律给 secondary 或 ghost;danger 是一种状态、不是一档强调,把它花在「只是重要」的东西上,等到真有什么是破坏性的时候,页面上就再没有东西读起来像破坏性的了。
sizes
同一个 variant 下的三个尺寸,于是变的只有那个盒子。几乎永远该拿 md:sm 在默认密度下是 36px,低于 md 自己就能达到的 44px,所以拿它拼出来的工具栏,是一排拇指按不中的目标(WCAG 2.5.5)——而 lg 是留给这一页真正在讲的那一个动作的。
states
一个正在飞行中的控件、一个被关掉的控件,以及一个把快捷键写在脸上的控件。用 loading,别自己手动换文案:它一步就把文案留住、把 aria-busy 设上、把点击挡掉,于是这个盒子不会在刚按中它的指针底下塌掉。那枚键帽是真的文字,会并进无障碍名称里,所以只有真的绑了这个键时才写它。
icon only
一个方形控件,只有一个图形、没有文字,用在文字只会把这一行已经说过的话再说一遍的工具栏里。iconOnly 不会在后面留下任何文字形状的东西,所以 aria-label 在这里不是可选项——一个没有它的图标按钮会被播报成「一个按钮」,没有名字,而这正是一套设计系统交付一个没人能用的控件最常见的方式。
类型
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'
export type ButtonSize = 'sm' | 'md' | 'lg'键盘操作
| 按键 | 作用 |
|---|---|
| Enter | 激活按钮。 |
| Space | 激活按钮。原生 <button> 两个键都认;套了样式的 <div> 一个都不认。 |
无障碍
- 默认渲染原生 <button>,所以 Enter 和 Space 都能触发。
- loading 会设置 aria-busy 并禁用控件;标签保持不变,按钮不会在刚被点下时缩掉、把页面往上抽。
- 链接无法被 disabled,所以 href + loading 用 aria-disabled 并挡掉指针事件。
- iconOnly 没有文字,因此必须给 aria-label——这是设计系统交付一个不可用控件最常见的方式。