ProForm adds some syntactic sugar and more layout settings to the original Form to help us develop a form quickly. Also add some default behaviors to make our forms work well by default.

Step-by-step forms, Modal forms, Drawer forms, Query forms, Lightweight filters and many other layouts can cover most of the usage scenarios and get rid of the complicated and tedious form layout work and do more with less code.

  • If you want to set default values, please use initialValues, any direct use of component value and onChange may cause value binding failure.

  • If you want to link forms or do some dependencies, you can use render props mode, ProFormDependency is definitely the best choice

  • ProForm's onFinish, unlike antd's Form, is a Promise that will automatically set the button to load for you if you return normally.

  • If you want to listen to a value, it is recommended to use onValuesChange. Keeping a unidirectional data flow is a great benefit for both developers and maintainers

  • ProForm has no black technology, it's just a wrapper for antd's Form, if you want to use a custom component you can wrap it with Form.

// Set overall default values
<ProForm initialValues={obj} />
// Set the individual control's
onValuesChange={(changeValues) => console.log(changeValues)}
<ProFormText initialValue="prop"/>
// Interdependent component linkage
<ProForm.Item noStyle shouldUpdate>
{(form) => {
return (
value: "chapter",
label: "Effective when stamped",
label={`with${form.getFieldValue("name")}contract agreement effective mode`}
// Using custom components
<ProForm.Item name="switch" label="Switch" valuePropName="checked">
<Switch />

Data conversion

Many times there is no exact match between the data required by the component and the data required by the backend, and ProForm provides two APIs to solve this problem, 'transform' and 'convertValue'.

convertValue Pre-conversion

convertValue occurs before the component obtains data, usually the data directly sent from the backend to the frontend, and sometimes needs to be refined.

export type SearchConvertKeyFn = (value: any, field: NamePath) => string | Record<string, any>;
* @name Converts the value when getting it, generally used to format the data into the format received by the component
* @param value field value
* @param namePath field name
* @returns the new value of the field
* @example a,b => [a,b] convertValue: (value,namePath)=> value.split(",")
* @example string => json convertValue: (value,namePath)=> JSON.parse(value)
* @example number => date convertValue: (value,namePath)=> Moment(value)
* @example YYYY-MM-DD => date convertValue: (value,namePath)=> Moment(value,"YYYY-MM-DD")
* @example string => object convertValue: (value,namePath)=> { return {value,label:value} }
convertValue?: SearchConvertKeyFn;

transform transform when submitting

Transform occurs when submitting, generally speaking, it is spit out the data stored in the database to the backend.

For the convenience of everyone, both ProFormDependency and formRef support transform, which can get the transformed value.

{(value, form) => {
// value is transformed by transform
// form's current formRef, you can get the unconverted value
return ReactNode;

formRef has several built-in methods to get the converted value, which is also more functional than antd's Form. For details, see the type definition of ProFormInstance.

/** Get all data formatted by ProForm */
getFieldsFormatValue?: (nameList?: true) => T;
/** Get the single data after formatting */
getFieldFormatValue?: (nameList?: NamePath) => T;
/** Get the single data after formatting */
getFieldFormatValueObject?: (nameList?: NamePath) => T;
/** After validating the fields, return all the data after formatting */
validateFieldsReturnFormatValue?: (nameList?: NamePath[]) => Promise<T>;
export type SearchTransformKeyFn = (
value: any,
namePath: string,
allValues: any,
) => string | Record<string, any>;
* @name Convert value when submitting, generally used to convert value into submitted data
* @param value field value
* @param namePath field name
* @param allValues ​​all fields
* The new value of the @returns field, if an object is returned, it will be merged with all values ​​once
* @example {name:[a,b] => {name:a,b } transform: (value,namePath,allValues)=> value.join(",")
* @example {name: string => { newName:string } transform: (value,namePath,allValues)=> { newName:value }
* @example {name:moment} => {name:string transform: (value,namePath,allValues)=> value.format("YYYY-MM-DD")
* @example {name:moment}=> {name:timestamp} transform: (value,namePath,allValues)=> value.valueOf()
* @example {name:{value,label}} => { name:string} transform: (value,namePath,allValues)=> value.value
* @example {name:{value,label}} => { valueName,labelName } transform: (value,namePath,allValues)=> { valueName:value.value, }
transform?: SearchTransformKeyFn;

When to Use

ProForm is the best choice when you want to implement a form quickly but don't want to spend too much time on layout.

Code examples

Basic Usage

Grid mode

supported in ProForm, SchemaForm, ModalForm, DrawerForm, StepsForm

Form's layout toggle