按钮与表单
按钮与表单组件统一操作反馈、输入外观和焦点样式。Button 提供四种外观与三种尺寸,IconButton 必须提供可访问名称;Segmented、Slider 和 Switch 由应用保存状态。DropdownSelect 提供统一主题的下拉菜单,以字符串回调更新选择;原生 Select 保留浏览器事件接口。字段组件把标签、说明和错误关联到控件,表单校验与提交由应用负责。
参考资料
效果展示
示例状态保存在当前组件中,刷新页面后恢复初始值。
按钮
| 属性 | 类型与默认值 | 用途 |
|---|---|---|
variant | primary、secondary、ghost、danger;默认 secondary | 操作层级 |
size | sm、md、lg;默认 md | 控件尺寸 |
leftIcon | ReactNode | 文字前的图标 |
fullWidth | boolean | 填满可用宽度 |
rounded | boolean | 胶囊形圆角 |
active | boolean | 按钮选中态,同时设置 aria-pressed |
Button 支持原生按钮属性和 ref,默认 type="button"。表单提交应显式设置 type="submit"。
import { Button, IconButton } from '@lailai0916/ui';
export function Actions() {
return (
<>
<Button variant="primary" type="submit">
保存
</Button>
<IconButton label="关闭" size="sm">
×
</IconButton>
</>
);
}
IconButton 的 label 必填。默认 variant="ghost",尺寸为 sm 或 md;顶部栏的搜索、导航等图标操作使用 variant="header",与语言和主题按钮共享圆角、悬停边框、按压、焦点与图标描边。顶部样式在桌面为 32 像素,在宽度不超过 980 像素或粗指针设备上为 44 像素,尺寸由该样式统一管理;图标推荐使用 17 像素。
import { Icon, IconButton } from '@lailai0916/ui';
<IconButton variant="header" label="搜索" title="搜索(⌘K / Ctrl+K)" onClick={openSearch}>
<Icon icon="lucide:search" width={17} />
</IconButton>;
两种外观均保留原生按钮属性、ref 与操作提示。示例中的搜索状态和 openSearch 由应用提供。
语言按钮
LanguageButton 接受 locale="en" | "zh-Hans" 和 onLocaleChange。按钮显示当前的“EN”或“中”,点击请求切换到另一种语言;翻译、保存偏好和路由由宿主管理。
默认提示与可访问名称说明当前语言及切换目标,也可通过 label 覆盖。悬停或键盘聚焦显示提示,Escape 关闭;桌面为 32 px,小于等于 980 px 或触摸设备增至 44 px。支持原生按钮属性与 ref,默认 type="button"。
示例只切换按钮状态。实际应用应把回调连接到自己的语言管理器。
选择与调整
| 组件 | 必要属性 | 可选属性与行为 |
|---|---|---|
Segmented | value、items;按钮模式提供 onChange | 默认纵向;orientation="horizontal" 横向;size="sm" 紧凑;ariaLabel 命名选择组 |
Slider | value、min、max、onChange | step、label、valueLabel、onCommit、aria-label |
Switch | checked、onChange | 用 aria-label 提供开关用途 |
Segmented.items 中每项包含 value 和 label,可附 icon。按钮模式采用单选组语义,通过方向键移动和选择。横向排列在 480 px 以下堆叠,也可指定 stackAt={360},或用 stackAt={0} 始终保持横向。
size 默认为 md。size="sm" 使用紧凑文字和 32 px 高的选项,在小屏或触摸设备上增至 44 px;选中块、圆角和焦点样式与默认尺寸一致。
导航模式给每一项设置 href,选中值由当前路由决定,此时不会调用 onChange。同一组不要混用按钮与链接。
import { useState } from 'react';
import { Segmented } from '@lailai0916/ui';
export function DensityControl() {
const [density, setDensity] = useState('compact');
return (
<Segmented
ariaLabel="显示密度"
orientation="horizontal"
value={density}
onChange={setDensity}
items={[
{ value: 'compact', label: '紧凑' },
{ value: 'comfortable', label: '宽松' },
]}
/>
);
}
Slider.onChange 接收数值,Switch.onChange 接收布尔值;它们与原生输入框的事件参数不同。
下拉选择
DropdownSelect 和 DropdownSelectField 从 0.3.5 起提供统一外观的单选菜单。触发按钮和展开列表均使用组件库样式,随宿主的浅色与深色主题切换。
选择导出文件的格式。
| 属性 | 类型与行为 |
|---|---|
options | 必填;每项包含字符串 value、字符串 label,可设 disabled;value 应唯一 |
value、onValueChange | 受控值与更新回调;回调接收新的字符串值 |
defaultValue | 非受控模式的初始值,与 value 二选一 |
placeholder | 尚未选择时显示的文字,不能代替标签 |
id、name | 控件 ID 与表单字段名;提供 name 后选中值可由 FormData 读取 |
disabled、required、invalid | 整个控件禁用、必填语义与错误状态 |
ref | 指向触发按钮,类型为 HTMLButtonElement |
import { useState } from 'react';
import { DropdownSelectField } from '@lailai0916/ui';
export function ExportFormatField() {
const [format, setFormat] = useState('json');
return (
<DropdownSelectField
label="导出格式"
name="format"
required
value={format}
onValueChange={setFormat}
description="选择导出文件的格式。"
options={[
{ value: 'json', label: 'JSON' },
{ value: 'csv', label: 'CSV' },
{ value: 'xlsx', label: 'Excel', disabled: true },
]}
/>
);
}
非受控模式使用 defaultValue;无初始选择时可设置 placeholder。基础组件应通过关联标签、aria-label 或 aria-labelledby 提供可访问名称。
import { DropdownSelect } from '@lailai0916/ui';
<DropdownSelect
aria-label="排列顺序"
name="sort"
defaultValue="updated"
options={[
{ value: 'updated', label: '最近更新' },
{ value: 'name', label: '名称' },
]}
/>;
DropdownSelectField 要求可见 label,支持 description、error 和 wrapperClassName。它自动生成 ID、关联说明和错误;传入 error 同时设置 aria-invalid。wrapperClassName 用于外层布局,className 用于触发按钮。颜色、圆角和阴影通过公开的 --lk-* 主题变量定制。
方向键移动选项,Enter 或空格确认,Home 和 End 跳至首尾,输入文字可定位选项,Escape 关闭菜单。禁用项不可选;长列表可滚动,弹层会根据可用空间调整位置。在 Dialog 内使用时,菜单保持在对话框内交互,不需要额外挂载主题 Provider。
Select 和 SelectField 仍使用原生 <select>,保留浏览器与系统的展开菜单。它们接受 <option> 子元素、原生 onChange 事件和 HTMLSelectElement ref;新下拉组件接受 options 数组、onValueChange(string) 和按钮 ref,不支持原生 multiple、size 或 <optgroup> 接口。替换时应同步调整属性与事件处理。
表单字段
TextField、TextAreaField 和 SelectField 分别接受原生 input、textarea、select 属性。三者均要求 label,支持 description、error,并自动生成字段 ID、连接说明与错误消息。
import { useState } from 'react';
import { SelectField, Stack, TextAreaField, TextField } from '@lailai0916/ui';
export function ProfileFields() {
const [email, setEmail] = useState('');
return (
<Stack>
<TextField
label="电子邮箱"
type="email"
autoComplete="email"
required
value={email}
onChange={(event) => setEmail(event.currentTarget.value)}
description="用于接收通知。"
/>
<TextAreaField label="备注" rows={3} defaultValue="" />
<SelectField label="语言" defaultValue="zh-Hans">
<option value="zh-Hans">简体中文</option>
<option value="en">English</option>
</SelectField>
</Stack>
);
}
校验失败时传入具体的 error 文案,组件会设置 aria-invalid 并关联错误消息。业务校验、请求状态与提交处理由宿主负责;不要把占位文字作为唯一标签。
原生控件与应用操作
Input、TextArea 和 Select 提供不带标签框架的基础控件,保留原生属性、事件与 ref。应用提供关联标签;通常优先使用 TextField、TextAreaField、SelectField。字段的 wrapperClassName 只安排外层布局,代码内容可使用 monospace。
PasswordInput 与 PasswordField 提供密码显隐,默认操作名称跟随 Provider 语言,也可设置 showLabel、hideLabel。显隐按钮不会提交表单,autoComplete 由应用选择。
Checkbox、Radio 必须提供可见 label,可附加 description;受控选中状态、name、value、disabled 与事件采用原生输入接口。
ButtonLink 接受 to 或 href,使用 Button 同款 variant、size、rounded、fullWidth 与 leftIcon,通过 Provider 接入路由。CopyButton 接受待复制的 value,默认反馈跟随语言,复制失败时明确提示;onCopied 与 onError 可接入应用处理。