Form 表单
表单容器——分组标题 + 行(label + 控件)+ 行间 hairline 分隔。
实时预览
下方渲染的就是 src/components/ui/Form/Form.tsx 本体,通过 react-native-web 翻译成浏览器节点。
基本信息
姓名 *
手机号 *
格式不正确
拜访设置
拜访提醒
同步给团队
API
来源:src/components/ui/Form/types.ts、{Form,FormGroup,FormRow}.tsx。
<Form>
| Prop | Type | 默认 | 说明 |
|---|---|---|---|
children | ReactNode | — | 通常是若干 FormGroup / FormRow;根容器纵向堆叠,组间 gap: space[7](16) |
testID | string? | — | E2E / 测试定位 |
<FormGroup>
| Prop | Type | 默认 | 说明 |
|---|---|---|---|
label | string? | — | 分组标题(uppercase 小标签风格);不传则不渲染标题行 |
children | ReactNode | — | 该分组下若干 FormRow;行间自动插 1px hairline 分隔(除首行外) |
testID | string? | — | E2E / 测试定位 |
<FormRow>
| Prop | Type | 默认 | 说明 |
|---|---|---|---|
label | string | — | 字段标题(左侧) |
children | ReactNode | — | 字段控件(Input / Switch 等,右侧) |
required | boolean? | false | 必填标记,label 后渲染红色 *(色值 c.error) |
error | string? | — | 错误信息,渲染在该行下方(红字) |
testID | string? | — | E2E / 测试定位 |
FormGroup动态列表(运行时增删FormRow)必须给每个 child 传稳定key;不传时 fallback 到__row-${i},仅适用于静态列表,动态列表会导致 state 漂移。
视觉规范
来源:src/components/ui/Form/styles.ts(值取自 src/theme/tokens.ts)。
| 元素 | 规则 |
|---|---|
| 分组标题 | t.xs(13)/ fw.semi(600)/ c.foregroundSubtle,全大写、letterSpacing: 1、paddingHorizontal: space[1](4) |
| 分组卡片 | c.surface 白底,radius.lg(10)圆角,overflow: hidden,组内 gap: space[3](8) |
| Form Row | minHeight: 48,左 label + 右控件,paddingHorizontal: space[7](16)/ paddingVertical: space[5](12) |
| 行 label | t.sm(14)/ fw.medium(500)/ c.foreground |
| 行间分隔 | StyleSheet.hairlineWidth、c.outline(亮色 #EDEDED)(这是 form 的例外,不用 gap) |
| 必填标记 | label 后带 *,色 c.error(亮色 #F4511E) |
| 错误提示 | 行下方 t.micro(11)/ c.error 红字 |
用法
import { Form, FormGroup, FormRow, Input, Switch } from '@unif/react-native-design';
<Form>
<FormGroup label="基本信息">
<FormRow label="姓名" required>
<Input value={name} onChangeText={setName} placeholder="请输入" />
</FormRow>
<FormRow label="手机号" error="格式不正确">
<Input value={phone} onChangeText={setPhone} keyboardType="phone-pad" />
</FormRow>
</FormGroup>
<FormGroup label="拜访设置">
<FormRow label="提醒">
<Switch value={remind} onChange={setRemind} />
</FormRow>
</FormGroup>
</Form>
无障碍(a11y)
来源:src/components/ui/Form/{Form,FormGroup,FormRow}.tsx、types.ts。
Form / FormGroup / FormRow 都是纯布局容器,源码全是 <View> + <Text>(分组标题 / 字段 label / 必填星号 / 错误文字),三者均未设置任何 a11y prop(无 accessibilityRole / accessibilityLabel / state),也无可传的 a11y prop。
- 真正的 a11y 语义来自传入
FormRow的控件 children(如 Input 的<TextInput>、Switch),由控件自身承载 role / label / state。 FormRow的label、必填*、error文字渲染为相邻<Text>,默认对 SR 可读,但未与控件做程序化关联(无accessibilityLabelledBy/ describedBy)。为确保 SR 把字段名读到对应控件上,建议在控件上显式补accessibilityLabel(如<Input accessibilityLabel="姓名" />),错误态可补accessibilityHint。
// label 是视觉文本;控件上显式补 accessibilityLabel 把字段名关联到输入
<FormRow label="姓名" required>
<Input value={name} onChangeText={setName} accessibilityLabel="姓名" />
</FormRow>
与 Cell · List 的区别
| 用途 | 选哪个 |
|---|---|
| 数据展示(设置项、客户列表) | Cell · List — 白卡 + gap |
| 数据录入(表单) | Form — 白卡 + 行间 hairline |
录入场景密度更高,hairline 分隔比 gap 更高效;展示场景反之。