#ProFormFields
ProForm comes with a significant number of form items, which are essentially a combination of Form.Item and components. Each form item supports the fieldProps property to support setting the props of the input component. We support pass-through of placeholder, so you can set placeholder directly on the component.
Each form item also supports readonly, which has different read-only styles for different components, making readonly display more friendly compared to disable. The generated dom is also smaller, e.g. ProFormDigit automatically formats decimal digits.
ProFormText is the product of FormItem + Input and can be analogous to the following code.
const ProFormText = (props) => {
return (
<ProForm.Item {...props}>
<Input placeholder={props.placeholder} {...props.fieldProps} />
</ProForm.Item>
);
};So the props we set for ProFormText are actually for Form.Item, and the fieldProps are for the included Input, remember.
#Component List
| Component | Usage Scenario |
|---|---|
| ProFormText | Suitable for various text inputs |
| ProFormDigit | Numeric input component with formatting support (default: two decimal places, minimum value: 0), formatting can be disabled if needed. |
| ProFormText.Password | Suitable for password input |
| ProFormTextArea | Supports multi-line text input, ideal for longer text content |
| ProFormCaptcha | Used for verification code input, typically combined with a verification code API |
| ProFormDatePicker | Date picker, suitable for selecting a single date |
| ProFormDateTimePicker | Date + Time picker, suitable for combined date and time selection scenarios |
| ProFormDateRangePicker | Date range picker, suitable for selecting a date range |
| ProFormDateTimeRangePicker | Date + Time range picker, suitable for selecting a date and time range |
| ProFormSelect | Supports generating options using request and valueEnum, suitable for selecting one item from multiple options. |
| ProFormTreeSelect | Supports generating options using request and valueEnum, suitable for tree-structured option selection. |
| ProFormCheckbox | Supports layout, and options can be generated using request and valueEnum |
| ProFormRadio.Group | Supports generating options using request and valueEnum, suitable for single-option selection with all options displayed |
| ProFormSlider | Suitable for selecting values within a numeric or custom range, supports continuous and discrete values. |
| ProFormSwitch | Suitable for toggling between two mutually exclusive options, typically true and false |
| ProFormUploadButton | Button-style file uploader |
| ProFormUploadDragger | Drag-and-drop file uploader, commonly used in prominent upload form areas |
| ProFormMoney | General-purpose monetary input component |
| ProFormSegmented | Segmented control for dividing options into sections |
#Code examples
import {
ProForm,
ProFormCascader,
ProFormCheckbox,
ProFormColorPicker,
ProFormDigit,
ProFormDigitRange,
ProFormGroup,
ProFormRadio,
ProFormRate,
ProFormSegmented,
ProFormSelect,
ProFormSlider,
ProFormSwitch,
ProFormText,
ProFormTreeSelect,
ProFormUploadButton,
ProFormUploadDragger,
} from '@ant-design/pro-components';
import { message, Switch } from 'antd';
import { useState } from 'react';
export const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const Demo = () => {
const [readonly, setReadonly] = useState(false);
return (
<div
style={{
padding: 24,
}}
>
<Switch
style={{
marginBlockEnd: 16,
}}
checked={readonly}
checkedChildren="Edit"
unCheckedChildren="Read Only"
onChange={setReadonly}
/>
<ProForm
readonly={readonly}
name="field-set-components-other-demo"
initialValues={{
name: 'demo_user',
password: 'demo123',
select: 'china',
select2: '520000201604258831',
useMode: { label: 'Unresolved', value: 'open', key: 'open' },
'select-multiple': ['green', 'blue'],
radio: 'a',
'radio-vertical': 'b',
'radio-button': 'b',
'checkbox-group': ['A', 'B', 'C'],
'input-number-range': [2, 4],
'input-number': 3,
switch: true,
slider: 66,
rate: 3.5,
segmented: 'open',
segmented2: 'open',
treeSelect: [
{
title: 'Child Node3',
value: '0-1-0',
},
],
}}
onFinish={async () => {
message.success('Submitted');
}}
>
<ProFormGroup title="Text Types">
<ProFormText width="md" name="name" label="Name" />
<ProFormText.Password width="md" name="password" label="Password" />
</ProFormGroup>
<ProFormGroup
title="Selection Types"
collapsible
style={{
gap: '0 32px',
}}
>
<ProFormSelect
name="select"
label="Select"
valueEnum={{
china: 'China',
usa: 'U.S.A',
}}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>
<ProFormSelect
name="select2"
label="Select with Search"
showSearch
debounceTime={300}
request={async ({ keyWords }) => {
await waitTime(100);
return [
{ value: keyWords, label: 'Target' },
{ value: '520000201604258831', label: 'Patricia Lopez' },
{ value: '520000198509222123', label: 'Jose Martinez' },
{ value: '210000200811194757', label: 'Elizabeth Thomas' },
{ value: '530000198808222758', label: 'Scott Anderson' },
{ value: '500000198703236285', label: 'George Jackson' },
{ value: '610000199906148074', label: 'Linda Hernandez' },
{ value: '150000197210168659', label: 'Sandra Hall' },
];
}}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>
<ProFormSelect
width="md"
fieldProps={{
labelInValue: true,
}}
request={async () => [
{ label: 'All', value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Resolved', value: 'closed' },
{ label: 'In Progress', value: 'processing' },
]}
name="useMode"
label="Contract Agreed Effective Method"
/>
<ProFormSelect
name="select-multiple"
label="Select[multiple]"
valueEnum={{
red: 'Red',
green: 'Green',
blue: 'Blue',
}}
fieldProps={{
mode: 'multiple',
}}
placeholder="Please select favorite colors"
rules={[
{
required: true,
message: 'Please select your favorite colors!',
type: 'array',
},
]}
/>
<ProFormCascader
label="Address"
request={async () => [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
]}
fieldProps={{
changeOnSelect: true,
}}
name="area"
/>
<ProFormTreeSelect
name="treeSelect"
label={'TreeSelect Request'}
placeholder="Please tree select"
allowClear
width={330}
secondary
request={async () => {
return [
{
title: 'Node1',
value: '0-0',
children: [
{
title: 'Child Node1',
value: '0-0-0',
},
],
},
{
title: 'Node2',
value: '0-1',
children: [
{
title: 'Child Node3',
value: '0-1-0',
},
{
title: 'Child Node4',
value: '0-1-1',
},
{
title: 'Child Node5',
value: '0-1-2',
},
],
},
];
}}
fieldProps={{
suffixIcon: null,
showSearch: {
autoClearSearchValue: true,
filterTreeNode: true,
treeNodeFilterProp: 'title',
onSearch: (value) => {
console.log('onSearch', value);
},
},
popupMatchSelectWidth: false,
labelInValue: true,
multiple: true,
fieldNames: {
label: 'title',
},
}}
/>
<ProFormRadio.Group
name="radio"
label="Radio.Group"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>
<ProFormRadio.Group
name="radio-vertical"
layout="vertical"
label="Radio.Group"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>
<ProFormRadio.Group
name="radio-button"
label="Radio.Button"
radioType="button"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>
<ProFormCheckbox.Group
name="checkbox-group"
label="Checkbox.Group"
options={['A', 'B', 'C', 'D', 'E', 'F']}
/>
<ProFormColorPicker label="Color Picker" name="color" />
</ProFormGroup>
<ProFormGroup title="Number Types">
<ProFormDigitRange
label="InputNumberRange"
name="input-number-range"
separator="-"
placeholder={['Min', 'Max']}
separatorWidth={60}
/>
<ProFormDigit
label="InputNumber"
name="input-number"
width="sm"
min={1}
max={10}
/>
<ProFormSwitch name="switch" label="Switch" />
<ProFormSlider
name="slider"
label="Slider"
width="lg"
marks={{
0: 'A',
20: 'B',
40: 'C',
60: 'D',
80: 'E',
100: 'F',
}}
/>
<ProFormRate name="rate" label="Rate" />
<ProFormUploadButton name="pic" label="Upload" />
<ProFormUploadDragger name="drag-pic" label="Drag and Drop Upload" />
<ProFormSegmented
name="segmented"
label="Segmented Control"
valueEnum={{
open: 'Unresolved',
closed: 'Resolved',
}}
/>
<ProFormSegmented
name="segmented2"
label="Segmented Control - Remote Data"
request={async () => [
{ label: 'All', value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Resolved', value: 'closed' },
{ label: 'In Progress', value: 'processing' },
]}
/>
</ProFormGroup>
</ProForm>
</div>
);
};
export default Demo;
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
import { Switch } from 'antd';
import { useState } from 'react';
export default () => {
const [readonly, setReadonly] = useState(false);
return (
<div
style={{
padding: 24,
}}
>
<Switch
style={{
marginBlockEnd: 16,
}}
checked={readonly}
checkedChildren="Edit"
unCheckedChildren="Read Only"
onChange={setReadonly}
/>
<ProForm name="search-select-demo" readonly={readonly}>
<ProForm.Group>
<ProFormSelect.SearchSelect
name="userQuery"
label="Query Selector - request"
fieldProps={{
labelInValue: true,
style: {
minWidth: 140,
},
}}
debounceTime={300}
request={async ({ keyWords = '' }) => {
return [
{ label: 'All', value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Unresolved (Assigned)', value: 'assignees' },
{ label: 'Resolved', value: 'closed' },
{ label: 'In Progress', value: 'processing' },
].filter(({ value, label }) => {
return value.includes(keyWords) || label.includes(keyWords);
});
}}
/>
<ProFormSelect.SearchSelect
name="userQuery2"
label="Query Selector - valueEnum"
fieldProps={{
style: {
minWidth: 140,
},
}}
valueEnum={{
all: { text: 'All', status: 'Default' },
open: {
text: 'Unresolved',
status: 'Error',
},
closed: {
text: 'Resolved',
status: 'Success',
},
processing: {
text: 'In Progress',
status: 'Processing',
},
}}
/>
<ProFormSelect.SearchSelect
name="userQuery3"
label="Query Selector - options"
fieldProps={{
labelInValue: false,
style: {
minWidth: 140,
},
}}
options={[
{ label: 'All', value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Resolved', value: 'closed' },
{ label: 'In Progress', value: 'processing' },
]}
/>
</ProForm.Group>
</ProForm>
</div>
);
};
import {
ProForm,
ProFormDependency,
ProFormFieldSet,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
import { Switch } from 'antd';
import { useState } from 'react';
export default () => {
const [readonly, setReadonly] = useState(false);
return (
<div
style={{
padding: 24,
}}
>
<Switch
style={{
marginBlockEnd: 16,
}}
checked={readonly}
checkedChildren="编辑"
unCheckedChildren="只读"
onChange={setReadonly}
/>
<ProForm
name="field-set-form-fieldset-demo"
readonly={readonly}
initialValues={{
list: ['1', '2', '3'],
}}
>
<ProForm.Item label="互相依赖的表单">
<ProFormDependency name={['list']}>
{({ list }) => {
return <div>{JSON.stringify(list, null, 2)}</div>;
}}
</ProFormDependency>
</ProForm.Item>
<ProFormFieldSet name="list" label="组件列表">
<ProFormText width="md" />
<ProFormSelect
width="md"
request={async () => [
{ label: '全部', value: 'all' },
{ label: '未解决', value: 'open' },
{ label: '已解决', value: 'closed' },
{ label: '解决中', value: 'processing' },
]}
name="useMode"
label="合同约定生效方式"
/>
<ProFormText width="md" />
</ProFormFieldSet>
<ProFormFieldSet
name="list"
label="组件列表- Input.Group"
type="group"
rules={[
{
validator: (_, value) => {
const [name, name1, name2] = value || [];
if (!name) {
throw new Error('第一个值不能为空');
}
if (!name1) {
throw new Error('第二个值不能为空');
}
if (!name2) {
throw new Error('第三个值不能为空');
}
},
},
]}
transform={(value: any) => ({
list: value,
startTime: value[0],
endTime: value[1],
})}
>
<ProFormText width="md" />
<ProFormText width="md" />
<ProFormText width="md" />
</ProFormFieldSet>
<ProFormFieldSet
name="list"
label="组件列表"
transform={(value: any) => ({
list: value,
startTime: value[0],
endTime: value[1],
})}
>
<ProFormText width="md" readonly />
-
<ProFormText width="md" readonly />
-
<ProFormText width="md" readonly />
</ProFormFieldSet>
</ProForm>
</div>
);
};
import {
ProForm,
ProFormDateMonthRangePicker,
ProFormDatePicker,
ProFormDateQuarterRangePicker,
ProFormDateRangePicker,
ProFormDateTimePicker,
ProFormDateTimeRangePicker,
ProFormDateWeekRangePicker,
ProFormDateYearRangePicker,
ProFormTimePicker,
} from '@ant-design/pro-components';
import { Switch } from 'antd';
import dayjs from 'dayjs';
import { useState } from 'react';
import { FIXED_BASE_DATE, FIXED_BASE_TIMESTAMP } from '../../mockData';
/** 与 FIXED_BASE_TIMESTAMP(2024-01-15 10:00)对齐:范围一律「起 ≤ 止」 */
const DAY_MS = 86400000;
const rangeStartTs = FIXED_BASE_TIMESTAMP - DAY_MS;
const rangeEndTs = FIXED_BASE_TIMESTAMP;
export default () => {
const [readonly, setReadonly] = useState(false);
return (
<div
style={{
padding: 24,
}}
>
<Switch
style={{
marginBlockEnd: 16,
}}
checked={readonly}
checkedChildren="编辑"
unCheckedChildren="只读"
onChange={setReadonly}
/>
<ProForm
name="field-set-datatime-demo"
readonly={readonly}
initialValues={{
date: FIXED_BASE_TIMESTAMP,
dateYm: FIXED_BASE_TIMESTAMP,
dateWeek: FIXED_BASE_DATE,
dateMonth: FIXED_BASE_TIMESTAMP,
dateQuarter: FIXED_BASE_TIMESTAMP,
dateYear: FIXED_BASE_TIMESTAMP,
dateTime: FIXED_BASE_TIMESTAMP,
time: '00:01:05',
timeRange: ['05:00:00', '11:00:00'],
dateWeekRange: [dayjs('2024-01-01'), dayjs('2024-01-13')],
dateMonthRange: [dayjs('2024-01-01'), dayjs('2024-03-01')],
dateQuarterRange: [dayjs('2024-01-01'), dayjs('2024-06-30')],
dateYearRange: [dayjs('2022-01-01'), dayjs('2024-01-01')],
dateTimeRange: [rangeStartTs, rangeEndTs],
dateRange: [rangeStartTs, rangeEndTs],
}}
onFinish={async (values) => {
console.log('field-set-datatime-demo submit:', values);
}}
>
<ProForm.Group title="日期相关">
<ProFormDatePicker name="date" label="日期" />
<ProFormDatePicker.Month
name="dateYm"
label="年月"
fieldProps={{
format: 'YY-MM',
}}
/>
<ProFormTimePicker name="time" label="时间" />
<ProFormTimePicker.RangePicker name="timeRange" label="时间范围" />
<ProFormDatePicker.Week name="dateWeek" label="周" />
<ProFormDateWeekRangePicker name="dateWeekRange" label="周范围" />
<ProFormDatePicker.Month name="dateMonth" label="月" />
<ProFormDateMonthRangePicker
name="dateMonthRange"
label="月范围"
/>
<ProFormDatePicker.Quarter name="dateQuarter" label="季度" />
<ProFormDateQuarterRangePicker
name="dateQuarterRange"
label="季度范围"
/>
<ProFormDatePicker.Year name="dateYear" label="年" />
<ProFormDateYearRangePicker name="dateYearRange" label="年范围" />
<ProFormDateTimePicker
name="dateTime"
label="日期时间"
fieldProps={{
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
}}
/>
<ProFormDateRangePicker name="dateRange" label="日期范围" />
<ProFormDateTimeRangePicker
name="dateTimeRange"
label="日期时间范围"
/>
</ProForm.Group>
</ProForm>
</div>
);
};
import {
ProForm,
ProFormUploadButton,
ProFormUploadDragger,
} from '@ant-design/pro-components';
const Demo = () => {
return (
<ProForm name="field-set-upload-demo">
<ProFormUploadButton
title="上传按钮的文本变啦"
name="upload"
label="Upload"
max={2}
fieldProps={{
name: 'file',
}}
action="/upload.do"
extra="extra"
/>
<ProFormUploadButton
name="upload"
label="Upload"
max={2}
fieldProps={{
name: 'file',
listType: 'picture-card',
}}
action="/upload.do"
extra="extra"
/>
<ProFormUploadDragger max={4} label="Dragger" name="dragger" />
</ProForm>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
import {
ProForm,
ProFormCheckbox,
ProFormDatePicker,
ProFormDateRangePicker,
ProFormDateTimePicker,
ProFormDateTimeRangePicker,
ProFormDependency,
ProFormDigit,
ProFormFieldSet,
ProFormList,
ProFormRadio,
ProFormRate,
ProFormSelect,
ProFormSlider,
ProFormSwitch,
ProFormText,
ProFormTimePicker,
ProFormUploadButton,
ProFormUploadDragger,
} from '@ant-design/pro-components';
import { message } from 'antd';
import { FIXED_BASE_TIMESTAMP } from '../../mockData';
const options = [
{ id: 1, label: '选项 A', value: 1 },
{ id: 2, label: '选项 B', value: 2 },
{ id: 3, label: '选项 C', value: 3 },
{ id: 4, label: '选项 D', value: 4 },
{ id: 5, label: '选项 E', value: 5 },
{ id: 6, label: '选项 F', value: 6 },
{ id: 7, label: '选项 G', value: 7 },
{ id: 8, label: '选项 H', value: 8 },
{ id: 9, label: '选项 I', value: 9 },
{ id: 10, label: '选项 J', value: 10 },
{ id: 11, label: '选项 K', value: 11 },
{ id: 12, label: '选项 L', value: 12 },
];
const Demo = () => (
<div
style={{
padding: 24,
}}
>
<ProForm
readonly
name="field-set-components-other-readonly-demo"
initialValues={{
'select-multiple': ['red', 'green'],
'select-multiple2': [1, 2, 3],
useMode: 'all',
switch: true,
'input-number': 3,
'checkbox-group': ['A', 'B'],
rate: 3.5,
name: '示例科技有限公司',
radio: 'a',
list: ['1', '2', '3'],
list2: ['1', '2', '3', '5'],
select: 'china',
'radio-button': 'a',
dragger: [
{
uid: '1',
name: '合同.pdf',
status: 'done',
response: 'Server Error 500', // custom error message to show
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
{
uid: '2',
name: '营业执照.jpg',
status: 'done',
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
{
uid: '3',
name: '身份证.jpg',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
],
upload: [
{
uid: '1',
name: '合同.pdf',
status: 'done',
response: 'Server Error 500', // custom error message to show
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
{
uid: '2',
name: '营业执照.jpg',
status: 'done',
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
{
uid: '3',
name: '身份证.jpg',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'https://gw.alipayobjects.com/zos/antfincdn/7%24YOiS6YIm/huaban.png',
},
],
date: FIXED_BASE_TIMESTAMP,
dateWeek: FIXED_BASE_TIMESTAMP,
dateMonth: FIXED_BASE_TIMESTAMP,
dateQuarter: FIXED_BASE_TIMESTAMP,
dateYear: FIXED_BASE_TIMESTAMP,
dateTime: FIXED_BASE_TIMESTAMP,
time: '00:01:05',
timeRange: ['05:00:00', '11:00:00'],
dateTimeRange: [
FIXED_BASE_TIMESTAMP,
FIXED_BASE_TIMESTAMP - 1000 * 60 * 60 * 24,
],
dateRange: [
FIXED_BASE_TIMESTAMP,
FIXED_BASE_TIMESTAMP - 1000 * 60 * 60 * 24,
],
}}
onFinish={async () => {
message.success('Submitted');
}}
>
<ProForm.Group title="基础数据">
<ProFormText
width="md"
name="name"
label="name"
fieldProps={{
prefix: 'prefix',
suffix: 'suffix',
}}
/>
<ProFormSelect
name="select"
label="Select"
valueEnum={{
china: 'China',
usa: 'U.S.A',
}}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>
<ProFormSelect
width="md"
request={async () => [
{ label: '全部', value: 'all' },
{ label: '未解决', value: 'open' },
{ label: '已解决', value: 'closed' },
{ label: '解决中', value: 'processing' },
]}
name="useMode"
label="合同约定生效方式"
/>
<ProFormSelect
name="select-multiple"
label="Select[multiple]"
valueEnum={{
red: 'Red',
green: 'Green',
blue: 'Blue',
}}
fieldProps={{
mode: 'multiple',
}}
placeholder="Please select favorite colors"
rules={[
{
required: true,
message: 'Please select your favorite colors!',
type: 'array',
},
]}
/>
<ProFormSelect
name="select-multiple2"
label="Select[multiple]"
options={options}
fieldProps={{
mode: 'multiple',
}}
placeholder="Please select favorite colors"
rules={[
{
required: true,
message: 'Please select your favorite colors!',
type: 'array',
},
]}
/>
<ProFormDigit
label="InputNumber"
name="input-number"
min={1}
max={10}
/>
<ProFormSwitch
name="switch"
label="Switch"
unCheckedChildren="不同意"
checkedChildren="同意"
/>
<ProFormSlider
name="slider"
label="Slider"
marks={{
0: 'A',
20: 'B',
40: 'C',
60: 'D',
80: 'E',
100: 'F',
}}
/>
</ProForm.Group>
<ProFormRadio.Group
name="radio"
label="Radio.Group"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>
<ProForm.Group>
<ProFormText hidden label="text1" />
<ProFormText label="text2" />
</ProForm.Group>
<ProFormRadio.Group
name="radio-button"
label="Radio.Button"
radioType="button"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>
<ProFormCheckbox.Group
name="checkbox-group"
label="Checkbox.Group"
options={['A', 'B', 'C', 'D', 'E', 'F']}
/>
<ProFormRate name="rate" label="Rate" />
<ProFormUploadButton
name="upload"
label="Upload"
max={2}
action="/upload.do"
extra="longgggggggggggggggggggggggggggggggggg"
/>
<ProFormList
name="textList"
label="地址列表"
initialValue={[
{
name: '书琰',
addr: '杭州市滨江区',
},
{
name: '逄一',
addr: '北京市海淀区',
},
]}
>
<ProFormText name="name" label="姓名" />
<ProFormText name="addr" label="地址" />
</ProFormList>
<ProFormFieldSet
name="list"
label="组件列表"
transform={(value: any) => ({ startTime: value[0], endTime: value[1] })}
>
<ProFormText width="md" />
-
<ProFormText width="md" />
-
<ProFormText width="md" />
</ProFormFieldSet>
<ProFormFieldSet
name="list2"
label="组件列表自动增加"
transform={(value: any) => ({ startTime: value[0], endTime: value[1] })}
>
{(value) => {
return value?.map((e, index) => {
return (
<ProFormText
key={index}
width="md"
fieldProps={{
value: e,
}}
/>
);
});
}}
</ProFormFieldSet>
<ProFormUploadDragger max={4} label="Dragger" name="dragger" />
<ProForm.Group title="日期相关分组">
<ProFormDatePicker name="date" label="日期" />
<ProFormDatePicker
name="date"
fieldProps={{
format: 'YY-MM',
}}
label="年月"
/>
<ProFormTimePicker name="time" label="时间" />
<ProFormTimePicker.RangePicker name="timeRange" label="时间区间" />
<ProFormDatePicker.Week name="dateWeek" label="周" />
<ProFormDatePicker.Month name="dateMonth" label="月" />
<ProFormDatePicker.Quarter name="dateQuarter" label="季度" />
<ProFormDatePicker.Year name="dateYear" label="年" />
<ProFormDateTimePicker
name="dateTime"
label="日期时间"
fieldProps={{
format: (value) => value.format('YYYY-MM-DD'),
}}
/>
<ProFormDateRangePicker name="dateRange" label="日期区间" />
<ProFormDateTimeRangePicker name="dateTimeRange" label="日期时间区间" />
</ProForm.Group>
<ProForm.Group title="其他相关分组">
<ProForm.Item label="互相依赖的表单">
<ProFormDependency name={['list']}>
{({ list }) => {
return <div>{JSON.stringify(list, null, 2)}</div>;
}}
</ProFormDependency>
</ProForm.Item>
<ProFormFieldSet name="list" label="组件列表">
<ProFormText width="md" />
<ProFormSelect
width="md"
request={async () => [
{ label: '全部', value: 'all' },
{ label: '未解决', value: 'open' },
{ label: '已解决', value: 'closed' },
{ label: '解决中', value: 'processing' },
]}
name="useMode"
label="合同约定生效方式"
/>
<ProFormText width="md" />
</ProFormFieldSet>
<ProFormFieldSet
name="list"
label="组件列表- Input.Group"
type="group"
rules={[
{
validator: (_, value) => {
const [name, name1, name2] = value || [];
if (!name) {
throw new Error('第一个值不能为空');
}
if (!name1) {
throw new Error('第二个值不能为空');
}
if (!name2) {
throw new Error('第三个值不能为空');
}
},
},
]}
transform={(value: any) => ({
list: value,
startTime: value[0],
endTime: value[1],
})}
>
<ProFormText width="md" />
<ProFormText width="md" />
<ProFormText width="md" />
</ProFormFieldSet>
<ProFormFieldSet
name="list"
label="组件列表"
transform={(value: any) => ({
list: value,
startTime: value[0],
endTime: value[1],
})}
>
<ProFormText width="md" />
-
<ProFormText width="md" />
-
<ProFormText width="md" />
</ProFormFieldSet>
</ProForm.Group>
</ProForm>
</div>
);
export default Demo;
import {
LightFilter,
ProFormFieldSet,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
export function App() {
return (
<div className="App">
<LightFilter
initialValues={{
name: [
{
label: '包含',
value: 'Like',
},
'123',
],
}}
placement={'bottomLeft'}
>
<ProFormFieldSet
label="筛选"
name={'name'}
transform={(value: any) => {
return {
filter: [
{
operator: value[0],
value: value[1],
},
],
};
}}
>
<ProFormSelect
fieldProps={{
labelInValue: true,
}}
valueEnum={{
Like: '包合',
NotLike: '不包合',
Eq: '等于',
NotEq: '不等于',
}}
/>
<ProFormText placeholder="请输入" />
</ProFormFieldSet>
</LightFilter>
</div>
);
}
export default () => (
<div style={{ padding: 24 }}>
<App />
</div>
);
#API
ProForm comes with Filed , which basically corresponds to the valueType one by one.
#Generic properties
| Parameters | Description | Type | Default |
|---|---|---|---|
| width | The length of the Field, we summarize the common Field lengths and suitable scenarios, support some enumeration "xs" , "s" , "m" , "l" , "x" | number | "xs" | "s" | "m" | "l" | "x" | - |
| rowProps | Passed to Row when grid mode is enabled, Applies only to ProFormGroup, ProFormList, ProFormFieldSet | RowProps | { gutter: 8 } |
| colProps | Passed to Col when grid mode is enabled | ColProps | { xs: 24 } |
| tooltip | will add an icon next to the label to show the configured information when hovered | string | tooltipProps | - |
| secondary | Whether secondary control, only valid for LightFilter | boolean | false |
| allowClear | Support for clearing, valid for LightFilter, will also be passed to fieldProps if actively set. | boolean | true |
#Width
In some cases, we need to adapt the input box according to the page display, except that a form area should use the fixed width rule by default.

XS=104pxfor short numbers, short text or options.S=216pxfor shorter field entries, such as name, phone, ID, etc.M=328pxStandard width, suitable for most field lengths.L=440pxSuitable for longer field entries, such as long URLs, tag groups, file paths, etc.XL=552pxSuitable for long text entry, such as long links, descriptions, notes, etc., usually used with adaptive multi-line input boxes or fixed height text fields.
#ProFormText
Same as Input.
<ProFormText
name="text"
label="Name"
placeholder="Please enter a name"
fieldProps={inputProps}
/>#ProFormCaptcha
ProFormCaptcha is a component developed to support common CAPTCHA functionality in the middle and backend.
import type { CaptFieldRef } from '@ant-design/pro-components';
import { ProForm, ProFormCaptcha } from '@ant-design/pro-components';
import { Button, message } from 'antd';
import { useRef } from 'react';
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const Demo = () => {
const captchaRef = useRef<CaptFieldRef | null | undefined>();
const inputRef = useRef();
return (
<ProForm
name="captcha-form-demo"
title="新建表单"
submitter={{
render: (props, doms) => {
return [
...doms,
<Button
htmlType="button"
onClick={() => {
captchaRef.current?.startTiming();
}}
key="start"
>
手动开始计数
</Button>,
<Button
htmlType="button"
onClick={() => {
captchaRef.current?.endTiming();
}}
key="end"
>
手动结束计数
</Button>,
];
},
}}
onFinish={async (_values) => {
await waitTime(2000);
message.success('提交成功');
return true;
}}
>
<ProFormCaptcha
onGetCaptcha={() => {
// dosomething()
return new Promise((resolve, reject) => {
reject();
});
}}
onTiming={(count) => {
if (count === 0) {
message.info('验证码倒计时结束');
}
}}
fieldRef={captchaRef}
fieldProps={{ ref: inputRef }}
name="code"
/>
</ProForm>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <MailTwoTone />,
}}
captchaProps={{
size: 'large',
}}
// The name of the phone number, which is injected by onGetCaptcha
phoneName="phone"
name="captcha"
rules={[
{
required: true,
message: 'Please enter the verification code',
},
]}
placeholder="Please enter a captcha"
// If you need to fail, you can throw an error and onGetCaptcha will stop automatically
// throw new Error("Error getting captcha")
onGetCaptcha={async (phone) => {
await waitTime(1000);
message.success(
`phone number ${phone} Verification code sent successfully! `,
);
}}
/>| Parameters | Description | Type | Default |
|---|---|---|---|
| onGetCaptcha | The event to click to get the captcha, if phoneName is configured it will be injected automatically | (phone)=>Promise<void> | - |
| phoneName | The name of the phone field, onGetCaptcha will inject its value | NamePath | - |
| onTiming | Listen to the countdown number | (count: number)=>void | - |
| captchaProps | The props of the Get Captcha button, same as antd's props | ButtonProps | - |
| countDown | The number of seconds to count down | number | 60 |
| captchaTextRender | Render the text of the timer | (timing: boolean, count: number) => React.ReactNode | - |
#ProFormText.Password
Same as Input.Password.
<ProFormText.Password label="InputPassword" name="input-password" />#ProFormTextArea
Same as Input.TextArea.
<ProFormTextArea
name="text"
label="name"
placeholder="Please enter a name"
fieldProps={inputTextAreaProps}
/>#ProFormDigit
Same as inputNumber. It comes with a formatting (retains 2 decimal places, minimum value is 0), you can turn it off if needed.
<ProFormDigit label="InputNumber" name="input-number" min={1} max={10} />If you want to change the number of decimal places.
<ProFormDigit
label="InputNumber"
name="input-number"
min={1}
max={10}
fieldProps={{ precision: 0 }}
/>#ProFormDigitRange
Same as inputNumber. It provides numeric range input.
<ProFormDigitRange label="InputNumberRange" name="input-number-range" />#ProFormDatePicker
Same as DatePicker.
<ProFormDatePicker name="date" label="date" />#ProFormDateTimePicker
Same as DatePicker.
<ProFormDateTimePicker name="datetime" label="datetime" />#ProFormDateRangePicker
Same as DatePicker.RangePicker.
<ProFormDateRangePicker name="dateRange" label="date" />#ProFormDateTimeRangePicker
Same as DatePicker.RangePicker.
<ProFormDateTimeRangePicker name="datetimeRange" label="datetime" />#ProFormTimePicker
Same as DatePicker
<ProFormDateRangePicker name="time" label="time" />#ProFormSelect
Same as select. Both request and valueEnum are supported to generate options.
Requesting remote data is more complicated, see here for details.
| Parameters | Description | Type | Default |
|---|---|---|---|
| valueEnum | Enumeration of current values valueEnum | Record | - |
| request | Enumerate data from network requests | ()=>Promise<{[key:string|number]:any}> | - |
| fetchDataOnSearch | Whether searching re-triggers request; set to false to fetch once on init and filter locally | boolean | true |
| debounceTime | Debounce time, used in conjunction with request | number | - |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | SelectProps | - |
Why support valueEnum when you have options? valueEnum can be used with tables, descriptions, and has engineering advantages.
<>
<ProFormSelect
name="select"
label="Select"
valueEnum={{
open: 'Unresolved',
closed: 'Resolved',
}}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>
<ProFormSelect
name="select2"
label="Select"
request={async () => [
{ label: 'all', value: 'all' }
{ label: 'Unresolved', value: 'open' }
{ label: 'Resolved', value: 'closed' }
{ label: 'Resolving', value: 'processing' },
]}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>
</>Related ProFormSelect
<ProFormText name="name" label="姓名" />
<ProFormSelect
name="addr"
width="md"
label="Selector linked with name"
// dependencies 的内容会注入 request 中
dependencies={['name']}
request={async (params) => [
{ label: params.name, value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Resolved', value: 'closed' },
{ label: 'Resolving', value: 'processing' },
]}
/>Customize options:
<ProFormSelect
name="select"
label="Select"
options={[
{ label: '全部', value: 'all' },
{ label: '未解决', value: 'open' },
{ label: '已解决', value: 'closed' },
{ label: '解决中', value: 'processing' },
]}
fieldProps={{
optionItemRender(item) {
return item.label + ' - ' + item.value;
},
}}
placeholder="Please select a country"
rules={[{ required: true, message: 'Please select your country!' }]}
/>#ProFormTreeSelect
Same as tree-select. Both request and valueEnum are supported to generate options.
Requesting remote data is more complicated, see here for details.
fieldProps.onOpenChange observes open state changes. The component still maintains its internal open state, so you do not need to pass open separately.
If virtual scrolling clips the final tree nodes, first upgrade antd and rc-virtual-list. On older versions, use fieldProps={{ virtual: false }} as a compatibility fallback.
Associated checking (treeCheckStrictly: false) does not add half-checked parents to the value. Derive them from the third onChange argument, extra.allCheckedNodes, or enable treeCheckStrictly when independent parent and child selection is acceptable.
| Parameters | Description | Type | Default |
|---|---|---|---|
| valueEnum | Enumeration of current values valueEnum | Record | - |
| request | Enumerate data from network requests | ()=>Promise<{[key:string|number]:any}> | - |
| debounceTime | Debounce time, used in conjunction with request | number | - |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | TreeSelectProps | - |
Why support valueEnum when you have options? valueEnum can be used with tables, descriptions, and has engineering advantages.
<ProFormTreeSelect
name="name"
placeholder="Please select"
allowClear
width={330}
secondary
request={async () => {
return [
{
title: 'Node1',
value: '0-0',
children: [
{
title: 'Child Node1',
value: '0-0-0',
},
],
},
{
title: 'Node2',
value: '0-1',
children: [
{
title: 'Child Node3',
value: '0-1-0',
},
{
title: 'Child Node4',
value: '0-1-1',
},
{
title: 'Child Node5',
value: '0-1-2',
},
],
},
];
}}
// tree-select args
fieldProps={{
suffixIcon: null,
filterTreeNode: true,
showSearch: true,
popupMatchSelectWidth: false,
labelInValue: true,
autoClearSearchValue: true,
multiple: true,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'title',
},
}}
/>#ProFormCheckbox
Requesting remote data is more complicated, see here for details.
Same as checkbox, but supports options and layout.
| Parameters | Description | Type | Default |
|---|---|---|---|
| options | Same as select, generates child nodes based on options, recommended. | string[] | {label:ReactNode,value:string}[] | - |
| layout | Configure the look of the checkbox to support vertical vertical and horizontal | horizontal | vertical | - |
| request | Enumerate data from network requests | ()=>Promise<{label,value}> | - |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | CheckboxProps | - |
<ProFormCheckbox.Group
name="checkbox"
layout="vertical"
label="Industry Distribution"
options={['Agriculture', 'Manufacturing', 'Internet']}
/>#ProFormRadio.Group
Requesting remote data is more complicated, see here for details.
Same as radio but with support for options.
| Parameters | Description | Type | Default |
|---|---|---|---|
| options | Same as select, generates child nodes based on options, recommended. | string[] | {label:ReactNode,value:string}[] | - |
| request | Enumerate data from network requests | ()=>Promise<{label,value}> | - |
| radioType | Set whether button mode or radio mode | default | button | default |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | RadioProps | - |
<ProFormRadio.Group
name="radio-group"
label="Radio.Group"
options={[
{
label: 'item 1',
value: 'a',
},
{
label: 'item 2',
value: 'b',
},
{
label: 'item 3',
value: 'c',
},
]}
/>#ProFormCascader
Same as cascader, configure Cascader data through fieldProps.
Requesting remote data is more complicated, see here for details.
<ProFormCascader
name="area"
label="Area"
fieldProps={{
options: [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
],
}}
/>| Parameters | Description | Type | Default |
|---|---|---|---|
| options | Similar to Cascader, generates child nodes based on options. It is recommended to use. | string[] | {label:ReactNode,value:string}[] | - |
| request | Enumerate data from network requests | ()=>Promise<{label,value}> | - |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | CascaderProps | - |
#ProFormSwitch
Same as switch, configure Switch data through fieldProps.
| Parameters | Description | Type | Default |
|---|---|---|---|
| fieldProps | Props of Ant Design component | SwitchProps | - |
<ProFormSwitch name="switch" label="Switch" />#ProFormRate
Same as rate, configure Rate data through fieldProps.
| Parameters | Description | Type | Default |
|---|---|---|---|
| fieldProps | Props of Ant Design component | RateProps | - |
<ProFormRate name="rate" label="Rate" />#ProFormSlider
Same as slider, configure Slider data through fieldProps.
| Parameters | Description | Type | Default |
|---|---|---|---|
| fieldProps | Props of Ant Design component | SliderProps | - |
<ProFormSlider
name="slider"
label="Slider"
marks={{
0: 'A',
20: 'B',
40: 'C',
60: 'D',
80: 'E',
100: 'F',
}}
/>#ProFormUploadDragger
Same as upload. Dragger style is preset, otherwise it is the same as Upload.
| Parameters | Description | Type | Default |
|---|---|---|---|
| icon | The chart of the Dragger. | ReactNode | InboxOutlined |
| title | Dragger's title | ReactNode | 'Click or drag files to this area to upload' |
| description | Dragger's description | ReactNode | 'Support single or bulk uploads' |
<ProFormUploadDragger label="Dragger" name="dragger" action="upload.do" />#ProFormUploadButton
Same as upload. The Button style is preset, otherwise it is the same as Upload.
| Parameters | Description | Type | Default |
|---|---|---|---|
| icon | The chart of Dragger. | ReactNode | UploadOutlined |
| title | Dragger's title | ReactNode | Click to upload |
| max | Maximum upload quantity. The upload button will be hidden if the maximum quantity is exceeded | number | - |
| buttonProps | Configuration of the upload button, e.g. buttonProps={{ type: "primary" }} | ButtonProps | - |
| disabled | Whether to disable the button | boolean | - |
| imageProps | Preview the additional configuration of the Image component, and you can customize the preview behavior, toolbar and other image component properties. | Omit<ImageProps, 'src'> | - |
<ProFormUploadButton label="upload" name="upload" action="upload.do" />#ProFormMoney
ProFormMoney's input box for entering amounts supports the display of currency symbols based on global internationalization, negative input, custom currency symbols, and more.
<ProFormMoney
label="The minimum limit is 0"
name="amount1"
locale="en-US"
initialValue={22.22}
min={0}
/>
<ProFormMoney
label="There is no limit to the amount size"
name="amount2"
locale="en-GB"
initialValue={22.22}
/>
<ProFormMoney
label="Currency symbols follow global internationalization"
name="amount3"
initialValue={22.22}
/>
<ProFormMoney
label="Custom currency symbols"
name="amount4"
initialValue={22.22}
customSymbol="💰"
/>| Parameters | Description | Type | Default |
|---|---|---|---|
| locale | The internationalized region values set separately show different currency symbols depending on the region, as detailed in the region directory below | string | zh-Hans-CN |
| customSymbol | Custom amount symbol | string | - |
| numberPopoverRender | Custom Popover's value, false, can close his | ((props: InputNumberProps, defaultText: string) => React.ReactNode) | boolean | false |
| numberFormatOptions | The configuration of NumberFormat, where the documentation can view the of the mdn) | NumberFormatOptions | - |
| min | The minimum value is | number | - |
| max | The maximum value is | number | - |
#Below is a table of regional codes and currency symbols
{
"ar-EG": "$",
"zh-CN": "¥",
"en-US": "$",
"en-GB": "£",
"vi-VN": "₫",
"it-IT": "€",
"ja-JP": "¥",
"es-ES": "€",
"ru-RU": "₽",
"sr-RS": "RSD",
"ms-MY": "RM",
"zh-TW": "NT$"
"fr-FR": "€",
"pt-BR": "R$",
"ko-KR": "₩",
"id-ID": "RP",
"de-DE": "€",
"fa-IR": "تومان",
"tr-TR": "₺",
"pl-PL": "zł",
"hr-HR": "kn",
}#ProFormSegmented
Same as Segmented. Supports both request and valueEnum methods to generate options.
Requesting remote data is more complicated, see here for details.
| Parameters | Description | Type | Default |
|---|---|---|---|
| valueEnum | Enumeration of current values valueEnum | Record | - |
| request | Enumerate data from network requests | ()=>Promise<{[key:string|number]:any}> | - |
| debounceTime | Debounce time, used in conjunction with request | number | - |
| params | Parameters for initiating network requests, used in conjunction with request. | Record | - |
| fieldProps | Props of Ant Design component | Segmented | - |
Why support valueEnum when you have options? valueEnum can be used with tables, descriptions, and has engineering advantages.
<>
<ProFormSegmented
name="segmented"
label="segmented"
valueEnum={{
open: 'Unresolved',
closed: 'Resolved',
}}
rules={[{ required: true, message: 'Please select your country!' }]}
/>
<ProFormSegmented
name="segmented"
label="segmented"
request={async () => [
{ label: 'All', value: 'all' },
{ label: 'Unresolved', value: 'open' },
{ label: 'Resolved', value: 'closed' },
{ label: 'In Progress', value: 'processing' },
]}
rules={[{ required: true, message: 'Please select your country!' }]}
/>
</>