跳到主要内容

Form 表单

组合表单分组、标签和字段的布局组件。

代码演示

基本信息
姓名 *
手机号 *
格式不正确
拜访设置
拜访提醒
同步给团队

API

来源:src/components/ui/Form/types.ts{Form,FormGroup,FormRow}.tsx

<Form>

参数类型默认值说明
childrenReactNode通常是若干 FormGroup / FormRow;根容器纵向堆叠,组间 gap: space[7](16)
testIDstring?E2E / 测试定位

<FormGroup>

参数类型默认值说明
labelstring?分组标题(uppercase 小标签风格);不传则不渲染标题行
childrenReactNode该分组下若干 FormRow;行间自动插 1px hairline 分隔(除首行外)
testIDstring?E2E / 测试定位

<FormRow>

参数类型默认值说明
labelstring字段标题(左侧)
childrenReactNode字段控件(Input / Switch 等,右侧)
requiredboolean?false必填标记,label 后渲染红色 *(色值 c.error
errorstring?错误信息,渲染在该行下方(红字)
testIDstring?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: 1paddingHorizontal: space[1](4)
分组卡片c.surface 白底,radius.lg(10)圆角,overflow: hidden,组内 gap: space[3](8)
Form RowminHeight: 48,左 label + 右控件,paddingHorizontal: space[7](16)/ paddingVertical: space[5](12)
行 labelt.sm(14)/ fw.medium(500)/ c.foreground
行间分隔StyleSheet.hairlineWidthc.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} accessibilityLabel="提醒" />
</FormRow>
</FormGroup>
</Form>;

Input / Textarea 严格模式

表单里的文本控件必须明确选择一种模式:受控时同时传 valueonChangeText;非受控时使用一次性的 defaultValue。不要混传 valuedefaultValue,也不要用已删除的 readOnly(改为 editable={false})。

<FormRow label="姓名">
<Input value={name} onChangeText={setName} accessibilityLabel="姓名" />
</FormRow>
<FormRow label="草稿">
<Textarea defaultValue="首次草稿" accessibilityLabel="草稿" />
</FormRow>
<FormRow label="拜访提醒">
<Switch
value={remind}
onChange={setRemind}
accessibilityLabel="拜访提醒"
/>
</FormRow>

无障碍(a11y)

来源:src/components/ui/Form/{Form,FormGroup,FormRow}.tsxtypes.ts

Form / FormGroup / FormRow 都是纯布局容器,源码全是 <View> + <Text>(分组标题 / 字段 label / 必填星号 / 错误文字),三者均未设置任何 a11y prop(无 accessibilityRole / accessibilityLabel / state),也无可传的 a11y prop。

  • 真正的 a11y 语义来自传入 FormRow控件 children(如 Input<TextInput>Switch),由控件自身承载 role / label / state;Switch 的 accessibilityLabel 是必填,必须与行标题一致或提供更明确的名称。
  • FormRowlabel、必填 *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 更高效;展示场景反之。设置列表若把 Switch / Stepper 放在 Cell 行尾,必须选择 Cell 的显式 control 分支,不能把控件 当作任意 ReactNode extra,也不能同时给 Cell 外层 onPress

<Cell
title="拜访提醒"
extra={{
kind: 'control',
node: (
<Switch
value={remind}
onChange={setRemind}
accessibilityLabel="拜访提醒"
/>
),
}}
/>