0% found this document useful (0 votes)
102 views1 page

Ant Design Dynamic Form Example

This document summarizes a high performance form component that allows for data collection, validation, and customization of styles. It can be used to create instances or collect information and validate fields with custom rules. Examples are provided for collecting username and password with optional fields, required fields, and dynamic adding or removing of form items. The component supports TypeScript, JavaScript, and CSS.

Uploaded by

rilfiun
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
102 views1 page

Ant Design Dynamic Form Example

This document summarizes a high performance form component that allows for data collection, validation, and customization of styles. It can be used to create instances or collect information and validate fields with custom rules. Examples are provided for collecting username and password with optional fields, required fields, and dynamic adding or removing of form items. The component supports TypeScript, JavaScript, and CSS.

Uploaded by

rilfiun
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Form Changelog

Required Mark (optional) Add field


High performance Form component with data scope management. Including data collection, verification, and styles.
Default Optional Hidden Customize
Add field at head

When to use Field A


Submit
When you need to create an instance or collect information. input placeholder

When you need to validate fields in certain rules.


Field B (optional)

input placeholder Dynamic Form Item


Examples Add or remove form items dynamically. add function support config initial value.
Submit

* Username :
TypeScript JavaScript CSS

Required style
* Password : import React from 'react';
Switch required or optional style with requiredMark .
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
Remember me import { Button, Form, Input } from 'antd';

Submit TypeScript JavaScript const formItemLayout = {

labelCol: {
import React, { useState } from 'react'; xs: { span: 24 },
import { InfoCircleOutlined } from '@ant-design/icons'; sm: { span: 4 },
Basic Usage import { Button, Form, Input, Radio, Tag } from 'antd'; },
Basic Form data control. Includes layout, initial values, validation and submit. wrapperCol: {
type RequiredMark = boolean | 'optional' | 'customize'; xs: { span: 24 },

sm: { span: 20 },
const customizeRequiredMark = (label: [Link], { required }: { required: boolean }) => ( },
TypeScript JavaScript
<> };
{required ? <Tag color="error">Required</Tag> : <Tag color="warning">optional</Tag>}
import React from 'react';
{label} const formItemLayoutWithOutLabel = {
import { Button, Checkbox, Form, Input } from 'antd';
</> wrapperCol: {
); xs: { span: 24, offset: 0 },
const onFinish = (values: any) => {
[Link]('Success:', values); sm: { span: 20, offset: 4 },
const App: [Link] = () => { },
};
const [form] = [Link](); };
const [requiredMark, setRequiredMarkType] = useState<RequiredMark>('optional');
const onFinishFailed = (errorInfo: any) => {
[Link]('Failed:', errorInfo); const App: [Link] = () => {
const onRequiredTypeChange = ({ requiredMarkValue }: { requiredMarkValue: RequiredMark }) => { const onFinish = (values: any) => {
};
setRequiredMarkType(requiredMarkValue); [Link]('Received values of form:', values);
}; };
type FieldType = {
username?: string;
return ( return (
password?: string;
<Form <Form
remember?: string;
form={form} name="dynamic_form_item"
};
layout="vertical" {...formItemLayoutWithOutLabel}
initialValues={{ requiredMarkValue: requiredMark }} onFinish={onFinish}
const App: [Link] = () => (
onValuesChange={onRequiredTypeChange} style={{ maxWidth: 600 }}
<Form
requiredMark={requiredMark === 'customize' ? customizeRequiredMark : requiredMark} >
name="basic"
> <[Link]
labelCol={{ span: 8 }}
<[Link] label="Required Mark" name="requiredMarkValue"> name="names"
wrapperCol={{ span: 16 }}
<[Link]> rules={[
style={{ maxWidth: 600 }}
<[Link] value>Default</[Link]> {
initialValues={{ remember: true }}
<[Link] value="optional">Optional</[Link]> validator: async (_, names) => {
onFinish={onFinish}
<[Link] value={false}>Hidden</[Link]> if (!names || [Link] < 2) {
onFinishFailed={onFinishFailed}
<[Link] value="customize">Customize</[Link]> return [Link](new Error('At least 2 passengers'));
autoComplete="off"
</[Link]> }
>
</[Link]> },
<[Link]<FieldType>
<[Link] label="Field A" required tooltip="This is a required field"> },
label="Username"
<Input placeholder="input placeholder" /> ]}
name="username"
</[Link]> >
rules={[{ required: true, message: 'Please input your username!' }]}
<[Link] {(fields, { add, remove }, { errors }) => (
>
label="Field B" <>
<Input />
tooltip={{ title: 'Tooltip with customize icon', icon: <InfoCircleOutlined /> }} {[Link]((field, index) => (
</[Link]>
> <[Link]
<Input placeholder="input placeholder" /> {...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
<[Link]<FieldType>
</[Link]> label={index === 0 ? 'Passengers' : ''}
label="Password"
<[Link]> required={false}
name="password"
<Button type="primary">Submit</Button> key={[Link]}
rules={[{ required: true, message: 'Please input your password!' }]}
</[Link]> >
>
</Form> <[Link]
<[Link] />
); {...field}
</[Link]>
}; validateTrigger={['onChange', 'onBlur']}

<[Link]<FieldType> rules={[
export default App; {
name="remember"
valuePropName="checked" required: true,
Hide
wrapperCol={{ offset: 8, span: 16 }} whitespace: true,

> message: "Please input passenger's name or delete this field.",

<Checkbox>Remember me</Checkbox> },

</[Link]> ]}
Form Size : Small Default Large
noStyle

<[Link] wrapperCol={{ offset: 8, span: 16 }}> >


Input :
<Button type="primary" htmlType="submit"> <Input placeholder="passenger name" style={{ width: '60%' }} />

Submit </[Link]>
Select :
</Button> {[Link] > 1 ? (

</[Link]> <MinusCircleOutlined
TreeSelect : className="dynamic-delete-button"
</Form>
); onClick={() => remove([Link])}
Cascader : />

export default App; ) : null}

DatePicker : Select date </[Link]>


Hide ))}

InputNumber : <[Link]>

<Button

type="dashed"
* Note : Switch :
onClick={() => add()}
style={{ width: '60%' }}
* Gender : Select a option and change input text above Button : Button
icon={<PlusOutlined />}

>
Submit Reset Fill form Add field

Form size </Button>


<Button
Set component size, only works for antd components.
type="dashed"
Form methods
onClick={() => {
Call form method with [Link] .
add('The head item', 0);
Note that useForm is a React Hooks that only works in functional component. TypeScript JavaScript }}

style={{ width: '60%', marginTop: '20px' }}


import React, { useState } from 'react';
icon={<PlusOutlined />}
import {
>
Button,
TypeScript JavaScript CSS Add field at head
Cascader,
</Button>
import React from 'react'; DatePicker,
<[Link] errors={errors} />
import { Button, Form, Input, Select } from 'antd'; Form,
</[Link]>
Input,
</>
const { Option } = Select; InputNumber,
)}
Radio,
</[Link]>
const layout = { Select,
<[Link]>
labelCol: { span: 8 }, Switch,
<Button type="primary" htmlType="submit">
wrapperCol: { span: 16 }, TreeSelect,
Submit
}; } from 'antd';
</Button>

</[Link]>
const tailLayout = { type SizeType = Parameters<typeof Form>[0]['size'];
</Form>
wrapperCol: { offset: 8, span: 16 },
);
}; const App: [Link] = () => {
};
const [componentSize, setComponentSize] = useState<SizeType | 'default'>('default');

const App: [Link] = () => {


export default App;
const [form] = [Link](); const onFormLayoutChange = ({ size }: { size: SizeType }) => {
setComponentSize(size);
Hide
const onGenderChange = (value: string) => { };

switch (value) {
case 'male': return (

[Link]({ note: 'Hi, man!' }); <Form Add field


break; labelCol={{ span: 4 }}

case 'female': wrapperCol={{ span: 14 }} Submit


[Link]({ note: 'Hi, lady!' }); layout="horizontal"

break; initialValues={{ size: componentSize }}

case 'other': onValuesChange={onFormLayoutChange}


Dynamic Form nest Items
[Link]({ note: 'Hi there!' }); size={componentSize as SizeType}

break; style={{ maxWidth: 600 }} Nest dynamic field need extends field . Pass [Link] to nest item.

default: >

} <[Link] label="Form Size" name="size">

}; <[Link]>
TypeScript JavaScript
<[Link] value="small">Small</[Link]>

const onFinish = (values: any) => { <[Link] value="default">Default</[Link]> import React from 'react';
[Link](values); <[Link] value="large">Large</[Link]> import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
}; </[Link]> import { Button, Form, Input, Space } from 'antd';
</[Link]>

const onReset = () => { <[Link] label="Input"> const onFinish = (values: any) => {
[Link](); <Input /> [Link]('Received values of form:', values);
}; </[Link]> };
<[Link] label="Select">

const onFill = () => { <Select> const App: [Link] = () => (


[Link]({ note: 'Hello world!', gender: 'male' }); <[Link] value="demo">Demo</[Link]> <Form
}; </Select> name="dynamic_form_nest_item"
</[Link]> onFinish={onFinish}
return ( <[Link] label="TreeSelect"> style={{ maxWidth: 600 }}
<Form <TreeSelect autoComplete="off"
{...layout} treeData={[ >
form={form} { title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] }, <[Link] name="users">
name="control-hooks" ]} {(fields, { add, remove }) => (
onFinish={onFinish} /> <>
style={{ maxWidth: 600 }} </[Link]> {[Link](({ key, name, ...restField }) => (
> <[Link] label="Cascader"> <Space key={key} style={{ display: 'flex', marginBottom: 8 }} align="baseline">
<[Link] name="note" label="Note" rules={[{ required: true }]}> <Cascader <[Link]
<Input /> options={[ {...restField}
</[Link]> { name={[name, 'first']}
<[Link] name="gender" label="Gender" rules={[{ required: true }]}> value: 'zhejiang', rules={[{ required: true, message: 'Missing first name' }]}
<Select label: 'Zhejiang', >
placeholder="Select a option and change input text above" children: [{ value: 'hangzhou', label: 'Hangzhou' }], <Input placeholder="First Name" />
onChange={onGenderChange} }, </[Link]>
allowClear ]} <[Link]
> /> {...restField}
<Option value="male">male</Option> </[Link]> name={[name, 'last']}
<Option value="female">female</Option> <[Link] label="DatePicker"> rules={[{ required: true, message: 'Missing last name' }]}
<Option value="other">other</Option> <DatePicker /> >
</Select> </[Link]> <Input placeholder="Last Name" />
</[Link]> <[Link] label="InputNumber"> </[Link]>
<[Link] <InputNumber /> <MinusCircleOutlined onClick={() => remove(name)} />
noStyle </[Link]> </Space>
shouldUpdate={(prevValues, currentValues) => [Link] !== [Link]} <[Link] label="Switch" valuePropName="checked"> ))}
> <Switch /> <[Link]>
{({ getFieldValue }) => </[Link]> <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
getFieldValue('gender') === 'other' ? ( <[Link] label="Button"> Add field
<[Link] name="customizeGender" label="Customize Gender" rules={[{ required: true }]}> <Button>Button</Button> </Button>
<Input /> </[Link]> </[Link]>
</[Link]> </Form> </>
) : null ); )}
} }; </[Link]>
</[Link]> <[Link]>
<[Link] {...tailLayout}> export default App; <Button type="primary" htmlType="submit">
<Button type="primary" htmlType="submit"> Submit
Submit Hide
</Button>
</Button> </[Link]>
<Button htmlType="button" onClick={onReset}> </Form>
Reset );
* Normal label
</Button>
<Button type="link" htmlType="button" onClick={onFill}> A super long export default App;
*
Fill form label text
</Button> Hide
</[Link]> Submit

</Form>
);
}; Item 1
label can wrap

Turn on labelWrap to wrap label if text is long. Name :


export default App;

Hide List : + Add Sub Item

TypeScript JavaScript

import React from 'react'; + Add Item


* Note : import { Button, Form, Input } from 'antd';
{
"items": [
* Gender : Select a option and change input text above const App: [Link] = () => ( {}
<Form ]
Submit Reset Fill form name="wrap" }

labelCol={{ flex: '110px' }}

labelAlign="left"
Complex Dynamic Form Item
labelWrap
Form methods (Class component) Multiple [Link] nested usage scenarios.
wrapperCol={{ flex: 1 }}
We recommend use [Link] to create data control. If you are using class component, you can get it by ref . colon={false}

style={{ maxWidth: 600 }}

>
TypeScript JavaScript
<[Link] label="Normal label" name="username" rules={[{ required: true }]}>
TypeScript JavaScript CSS
<Input /> import React from 'react';

import React from 'react'; </[Link]> import { CloseOutlined } from '@ant-design/icons';

import { Button, Form, Input, Select } from 'antd'; import { Button, Card, Form, Input, Space, Typography } from 'antd';

import type { FormInstance } from 'antd/es/form'; <[Link] label="A super long label text" name="password" rules={[{ required: true }]}>
<Input /> const App: [Link] = () => {

const { Option } = Select; </[Link]> const [form] = [Link]();

const layout = { <[Link] label=" "> return (

labelCol: { span: 8 }, <Button type="primary" htmlType="submit"> <Form

wrapperCol: { span: 16 }, Submit labelCol={{ span: 6 }}

}; </Button> wrapperCol={{ span: 18 }}

</[Link]> form={form}

const tailLayout = { </Form> name="dynamic_form_complex"

wrapperCol: { offset: 8, span: 16 }, ); style={{ maxWidth: 600 }}

}; autoComplete="off"

export default App; initialValues={{ items: [{}] }}

const App: [Link] = () => { >

const formRef = [Link]<FormInstance>(null); Hide <[Link] name="items">

{(fields, { add, remove }) => (

const onGenderChange = (value: string) => { <div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>

switch (value) { {[Link]((field) => (


* URL
case 'male': <Card
input placeholder
[Link]?.setFieldsValue({ note: 'Hi, man!' }); size="small"

break; title={`Item ${[Link] + 1}`}

case 'female': Submit Fill key={[Link]}

[Link]?.setFieldsValue({ note: 'Hi, lady!' }); extra={

break; <CloseOutlined

case 'other': onClick={() => {


No block rule
[Link]?.setFieldsValue({ note: 'Hi there!' }); remove([Link]);
rule with warningOnly will not block form submit.
break; }}

default: />

break; }

} TypeScript JavaScript >

}; <[Link] label="Name" name={[[Link], 'name']}>


import React from 'react'; <Input />

const onFinish = (values: any) => { import { Button, Form, Input, message, Space } from 'antd'; </[Link]>

[Link](values);
}; const App: [Link] = () => { {/* Nest [Link] */}
const [form] = [Link](); <[Link] label="List">

const onReset = () => { <[Link] name={[[Link], 'list']}>

[Link]?.resetFields(); const onFinish = () => { {(subFields, subOpt) => (

}; [Link]('Submit success!'); <div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}>
}; {[Link]((subField) => (

const onFill = () => { <Space key={[Link]}>

[Link]?.setFieldsValue({ note: 'Hello world!', gender: 'male' }); const onFinishFailed = () => { <[Link] noStyle name={[[Link], 'first']}>

}; [Link]('Submit failed!'); <Input placeholder="first" />


}; </[Link]>

return ( <[Link] noStyle name={[[Link], 'second']}>

<Form const onFill = () => { <Input placeholder="second" />

{...layout} [Link]({ </[Link]>

ref={formRef} url: '[Link] <CloseOutlined

name="control-ref" }); onClick={() => {

onFinish={onFinish} }; [Link]([Link]);

style={{ maxWidth: 600 }} }}

> return ( />

<[Link] name="note" label="Note" rules={[{ required: true }]}> <Form </Space>

<Input /> form={form} ))}

</[Link]> layout="vertical" <Button type="dashed" onClick={() => [Link]()} block>

<[Link] name="gender" label="Gender" rules={[{ required: true }]}> onFinish={onFinish} + Add Sub Item

<Select onFinishFailed={onFinishFailed} </Button>

placeholder="Select a option and change input text above" autoComplete="off" </div>

onChange={onGenderChange} > )}

allowClear <[Link] </[Link]>

> name="url" </[Link]>

<Option value="male">male</Option> label="URL" </Card>

<Option value="female">female</Option> rules={[{ required: true }, { type: 'url', warningOnly: true }, { type: 'string', min: 6 }]} ))}

<Option value="other">other</Option> >

</Select> <Input placeholder="input placeholder" /> <Button type="dashed" onClick={() => add()} block>

</[Link]> </[Link]> + Add Item

<[Link] <[Link]> </Button>

noStyle <Space> </div>

shouldUpdate={(prevValues, currentValues) => [Link] !== [Link]} <Button type="primary" htmlType="submit"> )}

> Submit </[Link]>

{({ getFieldValue }) => </Button>

getFieldValue('gender') === 'other' ? ( <Button htmlType="button" onClick={onFill}> <[Link] noStyle shouldUpdate>

<[Link] name="customizeGender" label="Customize Gender" rules={[{ required: true }]}> Fill {() => (

<Input /> </Button> <Typography>

</[Link]> </Space> <pre>{[Link]([Link](), null, 2)}</pre>

) : null </[Link]> </Typography>

} </Form> )}

</[Link]> ); </[Link]>

<[Link] {...tailLayout}> }; </Form>

<Button type="primary" htmlType="submit"> );

Submit export default App; };

</Button>
Hide
<Button htmlType="button" onClick={onReset}> export default App;

Reset
</Button> Hide

<Button type="link" htmlType="button" onClick={onFill}> Name (Watch to trigger rerender)


Fill form
</Button>
* Name :
</[Link]>
Age (Not Watch)
</Form>
Email :
);
};
Name Value: Age :

export default App;


Website :
Hide Watch Hooks

useWatch helps watch the field change and only re-render for the value change. API Ref.
Introduction :

Form Layout : Horizontal Vertical Inline


TypeScript JavaScript Submit

Field A : input placeholder


import React from 'react';

import { Form, Input, InputNumber, Typography } from 'antd';


Field B : input placeholder Nest

const Demo: [Link] = () => { name prop support nest data structure. Customize validate message template with validateMessages or message . Ref here about message template.

Submit const [form] = [Link]<{ name: string; age: number }>();

const nameValue = [Link]('name', form);

TypeScript JavaScript
return (
Form Layout
<> import React from 'react';
There are three layout for form: horizontal , vertical , inline .
<Form form={form} layout="vertical" autoComplete="off"> import { Button, Form, Input, InputNumber } from 'antd';

<[Link] name="name" label="Name (Watch to trigger rerender)">


<Input /> const layout = {

TypeScript JavaScript </[Link]> labelCol: { span: 8 },

<[Link] name="age" label="Age (Not Watch)"> wrapperCol: { span: 16 },


import React, { useState } from 'react'; <InputNumber /> };
import { Button, Form, Input, Radio } from 'antd'; </[Link]>
</Form> /* eslint-disable no-template-curly-in-string */
type LayoutType = Parameters<typeof Form>[0]['layout']; const validateMessages = {

<Typography> required: '${label} is required!',


const App: [Link] = () => { <pre>Name Value: {nameValue}</pre> types: {
const [form] = [Link](); </Typography> email: '${label} is not a valid email!',
const [formLayout, setFormLayout] = useState<LayoutType>('horizontal'); </> number: '${label} is not a valid number!',

); },
const onFormLayoutChange = ({ layout }: { layout: LayoutType }) => { }; number: {
setFormLayout(layout); range: '${label} must be between ${min} and ${max}',
}; export default Demo; },
};
const formItemLayout = Hide /* eslint-enable no-template-curly-in-string */
formLayout === 'horizontal' ? { labelCol: { span: 4 }, wrapperCol: { span: 14 } } : null;

const onFinish = (values: any) => {


const buttonItemLayout = [Link](values);
formLayout === 'horizontal' ? { wrapperCol: { span: 14, offset: 4 } } : null; Use 'max' rule, continue type chars to see it
};
Field A
return ( const App: [Link] = () => (
sss
<Form <Form
{...formItemLayout}
Field B {...layout}
layout={formLayout} name="nest-messages"
sss
form={form} onFinish={onFinish}
initialValues={{ layout: formLayout }} style={{ maxWidth: 600 }}
Field C
onValuesChange={onFormLayoutChange} validateMessages={validateMessages}
style={{ maxWidth: formLayout === 'inline' ? 'none' : 600 }} rrrrrryy >
> Field C must be up to 6 characters <[Link] name={['user', 'name']} label="Name" rules={[{ required: true }]}>
<[Link] label="Form Layout" name="layout"> <Input />
<[Link] value={formLayout}> </[Link]>
Validate Trigger
<[Link] value="horizontal">Horizontal</[Link]> <[Link] name={['user', 'email']} label="Email" rules={[{ type: 'email' }]}>
For the async validation scenario, too frequent verification will cause backend pressure. You can change the verification timing through validateTrigger , or change the verification frequency through validateDebounce , or set the verification short circuit through validateFirst .
<[Link] value="vertical">Vertical</[Link]> <Input />
<[Link] value="inline">Inline</[Link]> </[Link]>
</[Link]> <[Link] name={['user', 'age']} label="Age" rules={[{ type: 'number', min: 0, max: 99 }]}>
</[Link]> TypeScript JavaScript <InputNumber />
<[Link] label="Field A"> </[Link]>
<Input placeholder="input placeholder" /> import React from 'react'; <[Link] name={['user', 'website']} label="Website">
</[Link]> import { Alert, Form, Input } from 'antd'; <Input />
<[Link] label="Field B"> </[Link]>
<Input placeholder="input placeholder" /> const App: [Link] = () => ( <[Link] name={['user', 'introduction']} label="Introduction">
</[Link]> <Form name="trigger" style={{ maxWidth: 600 }} layout="vertical" autoComplete="off"> <[Link] />
<[Link] {...buttonItemLayout}> <Alert message="Use 'max' rule, continue type chars to see it" /> </[Link]>
<Button type="primary">Submit</Button> <[Link] wrapperCol={{ ...[Link], offset: 8 }}>
</[Link]> <[Link] <Button type="primary" htmlType="submit">
</Form> hasFeedback Submit
); label="Field A" </Button>
}; name="field_a" </[Link]>
validateTrigger="onBlur" </Form>
export default App; rules={[{ max: 3 }]} );
>
Hide <Input placeholder="Validate required onBlur" /> export default App;
</[Link]>

Hide
<[Link]
Form disabled
hasFeedback
Checkbox : Checkbox
label="Field B"
Username : Please input Need Help?
name="field_b"
Radio : Apple Pear
validateDebounce={1000}

rules={[{ max: 3 }]} Address : Select province Input street


Input : >

<Input placeholder="Validate required debounce after 1s" /> BirthDate : Input birth year Input birth month
Select : </[Link]>

Submit
TreeSelect : <[Link]

hasFeedback

Cascader : label="Field C"


complex form control
name="field_c"

validateFirst This demo shows how to use [Link] with multiple controls. <[Link] name="field" /> will only bind the control(Input/Select) which is the only children of it. Imagine this case: you added some text description after the Input, then you have to wrap the Input by an extra <[Link] name="field"> . style property of [Link] could be useful to modify the nested form item layout, or use <[Link] noStyle /> to turn it into a pure form-binded component(like getFieldDecorator in 3.x).
DatePicker : Select date
rules={[{ max: 6 }, { max: 3, message: 'Continue input to exceed 6 chars' }]}
>
RangePicker : Start date End date
<Input placeholder="Validate one by one" />
TypeScript JavaScript
</[Link]>
InputNumber :
</Form> import React from 'react';
); import { Button, Form, Input, Select, Space, Tooltip, Typography } from 'antd';
TextArea :

export default App; const { Option } = Select;

Hide
const onFinish = (values: any) => {

[Link]('Received values of form: ', values);


Switch :
};

* Name
Upload :
const App: [Link] = () => (
<Form
Upload
name="complex-form"
* Age
onFinish={onFinish}
labelCol={{ span: 8 }}
Button : Button
wrapperCol={{ span: 16 }}

Submit Reset style={{ maxWidth: 600 }}


Slider : >

<[Link] label="Username">
<Space>
Validate Only
<[Link]
Form disabled Dynamic adjust submit button's disabled status by validateOnly of validateFields . name="username"
Set component disabled, only works for antd components.
noStyle

rules={[{ required: true, message: 'Username is required' }]}

TypeScript JavaScript >

TypeScript JavaScript <Input style={{ width: 160 }} placeholder="Please input" />


import React from 'react'; </[Link]>
import { PlusOutlined } from '@ant-design/icons'; import type { FormInstance } from 'antd'; <Tooltip title="Useful information">
import React, { useState } from 'react'; import { Button, Form, Input, Space } from 'antd'; <[Link] href="#API">Need Help?</[Link]>
import { </Tooltip>
Button, const SubmitButton = ({ form }: { form: FormInstance }) => { </Space>
Cascader, const [submittable, setSubmittable] = [Link](false); </[Link]>
Checkbox, <[Link] label="Address">
DatePicker, // Watch all values <[Link]>
Form, const values = [Link]([], form); <[Link]
Input, name={['address', 'province']}
InputNumber, [Link](() => { noStyle
Radio, [Link]({ validateOnly: true }).then( rules={[{ required: true, message: 'Province is required' }]}
Select, () => { >
Slider, setSubmittable(true); <Select placeholder="Select province">
Switch, }, <Option value="Zhejiang">Zhejiang</Option>
TreeSelect, () => { <Option value="Jiangsu">Jiangsu</Option>
Upload, setSubmittable(false); </Select>
} from 'antd'; }, </[Link]>
); <[Link]
const { RangePicker } = DatePicker; }, [values]); name={['address', 'street']}
const { TextArea } = Input; noStyle
return ( rules={[{ required: true, message: 'Street is required' }]}
const normFile = (e: any) => { <Button type="primary" htmlType="submit" disabled={!submittable}> >
if ([Link](e)) { Submit <Input style={{ width: '50%' }} placeholder="Input street" />
return e; </Button> </[Link]>
} ); </[Link]>
return e?.fileList; }; </[Link]>
}; <[Link] label="BirthDate" style={{ marginBottom: 0 }}>
const App: [Link] = () => { <[Link]
const FormDisabledDemo: [Link] = () => { const [form] = [Link](); name="year"
const [componentDisabled, setComponentDisabled] = useState<boolean>(true); rules={[{ required: true }]}
return ( style={{ display: 'inline-block', width: 'calc(50% - 8px)' }}
return ( <Form form={form} name="validateOnly" layout="vertical" autoComplete="off"> >
<> <[Link] name="name" label="Name" rules={[{ required: true }]}> <Input placeholder="Input birth year" />
<Checkbox <Input /> </[Link]>
checked={componentDisabled} </[Link]> <[Link]
onChange={(e) => setComponentDisabled([Link])} <[Link] name="age" label="Age" rules={[{ required: true }]}> name="month"
> <Input /> rules={[{ required: true }]}
Form disabled </[Link]> style={{ display: 'inline-block', width: 'calc(50% - 8px)', margin: '0 8px' }}
</Checkbox> <[Link]> >
<Form <Space> <Input placeholder="Input birth month" />
labelCol={{ span: 4 }} <SubmitButton form={form} /> </[Link]>
wrapperCol={{ span: 14 }} <Button htmlType="reset">Reset</Button> </[Link]>
layout="horizontal" </Space> <[Link] label=" " colon={false}>
disabled={componentDisabled} </[Link]> <Button type="primary" htmlType="submit">
style={{ maxWidth: 600 }} </Form> Submit
> ); </Button>
<[Link] label="Checkbox" name="disabled" valuePropName="checked"> }; </[Link]>
<Checkbox>Checkbox</Checkbox> </Form>
</[Link]> export default App; );
<[Link] label="Radio">

<[Link]> Hide export default App;


<Radio value="apple"> Apple </Radio>

<Radio value="pear"> Pear </Radio> Hide


</[Link]>
First Name
</[Link]>

<[Link] label="Input">
<Input />
Last Name
</[Link]>
<[Link] label="Select">

<Select>
<[Link] value="demo">Demo</[Link]> Age
</Select>
</[Link]>

<[Link] label="TreeSelect">
Submit
<TreeSelect

treeData={[
{ title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] }, Path Prefix
]}
In some scenarios, you may want to set a prefix for some fields consistently. You can achieve this effect with HOC.
/>

</[Link]>
<[Link] label="Cascader">

<Cascader TypeScript JavaScript

options={[
import React from 'react';
{
import { Form, Input, Button } from 'antd';
value: 'zhejiang',
import type { FormItemProps } from 'antd';
label: 'Zhejiang',
children: [
const MyFormItemContext = [Link]<(string | number)[]>([]);
{

value: 'hangzhou',
interface MyFormItemGroupProps {
label: 'Hangzhou',
prefix: string | number | (string | number)[];
},
children: [Link];
],
}
},
]}
function toArr(str: string | number | (string | number)[]): (string | number)[] {
/>
return [Link](str) ? str : [str];
</[Link]>
}
<[Link] label="DatePicker">
<DatePicker />
const MyFormItemGroup = ({ prefix, children }: MyFormItemGroupProps) => {
</[Link]>
const prefixPath = [Link](MyFormItemContext);
<[Link] label="RangePicker">
const concatPath = [Link](() => [...prefixPath, ...toArr(prefix)], [prefixPath, prefix]);
<RangePicker />
</[Link]>
return <[Link] value={concatPath}>{children}</[Link]>;
<[Link] label="InputNumber">
};
<InputNumber />

</[Link]>
const MyFormItem = ({ name, ...props }: FormItemProps) => {
<[Link] label="TextArea">
const prefixPath = [Link](MyFormItemContext);
<TextArea rows={4} />
const concatName = name !== undefined ? [...prefixPath, ...toArr(name)] : undefined;
</[Link]>

<[Link] label="Switch" valuePropName="checked">


return <[Link] name={concatName} {...props} />;
<Switch />
};
</[Link]>

<[Link] label="Upload" valuePropName="fileList" getValueFromEvent={normFile}>


const App: [Link] = () => {
<Upload action="/[Link]" listType="picture-card">
const onFinish = (value: object) => {
<div>
[Link](value);
<PlusOutlined />
};
<div style={{ marginTop: 8 }}>Upload</div>
</div>
return (
</Upload>
<Form name="form_item_path" layout="vertical" onFinish={onFinish}>
</[Link]>
<MyFormItemGroup prefix={['user']}>
<[Link] label="Button">
<MyFormItemGroup prefix={['name']}>
<Button>Button</Button>
<MyFormItem name="firstName" label="First Name">
</[Link]>
<Input />
<[Link] label="Slider">
</MyFormItem>
<Slider />
<MyFormItem name="lastName" label="Last Name">
</[Link]>
<Input />
</Form>
</MyFormItem>
</>
</MyFormItemGroup>
);
};
<MyFormItem name="age" label="Age">

<Input />
export default () => <FormDisabledDemo />;
</MyFormItem>

</MyFormItemGroup>
Hide

<Button type="primary" htmlType="submit">

Submit

</Button>
</Form>

);

};

export default App;

Hide

Price : 0 RMB Submit * E-mail :

* Password :
Customized Form Controls

Customized or third-party form controls can be used in Form, too. Controls must follow these conventions:
* Confirm Password :
It has a controlled property value or other name which is equal to the value of valuePropName .
It has event onChange or an event which name is equal to the value of trigger .
* Nickname :

* Habitual Residence : Zhejiang / Hangzhou / West Lake

TypeScript JavaScript
* Phone Number : +86
import React, { useState } from 'react';

import { Button, Form, Input, Select } from 'antd';


* Donation :

const { Option } = Select;


* Website : website

type Currency = 'rmb' | 'dollar';


* Intro :

interface PriceValue {
0 / 100
number?: number;

currency?: Currency; * Gender : select your gender

}
Captcha : Get captcha
interface PriceInputProps { We must make sure that your are a human.
value?: PriceValue;
onChange?: (value: PriceValue) => void; I have read the agreement
}

Register
const PriceInput: [Link]<PriceInputProps> = ({ value = {}, onChange }) => {
const [number, setNumber] = useState(0);
const [currency, setCurrency] = useState<Currency>('rmb');
Registration

const triggerChange = (changedValue: { number?: number; currency?: Currency }) => { Fill in this form to create a new account for you.

onChange?.({ number, currency, ...value, ...changedValue });


};

TypeScript JavaScript
const onNumberChange = (e: [Link]<HTMLInputElement>) => {
const newNumber = parseInt([Link] || '0', 10); import React, { useState } from 'react';
if ([Link](number)) { import type { CascaderProps } from 'antd';
return; import {
} AutoComplete,
if (!('number' in value)) { Button,
setNumber(newNumber); Cascader,
} Checkbox,
triggerChange({ number: newNumber }); Col,
}; Form,

Input,
const onCurrencyChange = (newCurrency: Currency) => { InputNumber,
if (!('currency' in value)) { Row,
setCurrency(newCurrency); Select,
} } from 'antd';
triggerChange({ currency: newCurrency });

}; const { Option } = Select;

return ( interface DataNodeType {


<span> value: string;
<Input label: string;
type="text" children?: DataNodeType[];
value={[Link] || number} }
onChange={onNumberChange}

style={{ width: 100 }} const residences: CascaderProps<DataNodeType>['options'] = [


/> {
<Select value: 'zhejiang',
value={[Link] || currency} label: 'Zhejiang',
style={{ width: 80, margin: '0 8px' }} children: [
onChange={onCurrencyChange} {
> value: 'hangzhou',
<Option value="rmb">RMB</Option> label: 'Hangzhou',
<Option value="dollar">Dollar</Option> children: [
</Select> {
</span> value: 'xihu',
); label: 'West Lake',
}; },

],
const App: [Link] = () => { },
const onFinish = (values: any) => { ],
[Link]('Received values from form: ', values); },
}; {

value: 'jiangsu',
const checkPrice = (_: any, value: { number: number }) => { label: 'Jiangsu',
if ([Link] > 0) { children: [
return [Link](); {
} value: 'nanjing',
return [Link](new Error('Price must be greater than zero!')); label: 'Nanjing',
}; children: [
{
return ( value: 'zhonghuamen',
<Form label: 'Zhong Hua Men',
name="customized_form_controls" },
layout="inline" ],
onFinish={onFinish} },
initialValues={{ ],
price: { },
number: 0, ];
currency: 'rmb',
}, const formItemLayout = {
}} labelCol: {
> xs: { span: 24 },
<[Link] name="price" label="Price" rules={[{ validator: checkPrice }]}> sm: { span: 8 },
<PriceInput /> },
</[Link]> wrapperCol: {
<[Link]> xs: { span: 24 },
<Button type="primary" htmlType="submit"> sm: { span: 16 },
Submit },
</Button> };
</[Link]>
</Form> const tailFormItemLayout = {
); wrapperCol: {
}; xs: {

span: 24,
export default App; offset: 0,
},
Hide
sm: {
span: 16,
offset: 8,

},
* Username : Ant Design
},

};
[
{
const App: [Link] = () => {
"name": [
"username" const [form] = [Link]();
],
"value": "Ant Design" const onFinish = (values: any) => {
}
[Link]('Received values of form: ', values);
]
};

const prefixSelector = (
Store Form Data into Upper Component
<[Link] name="prefix" noStyle>
We can store form data into upper component or Redux or dva by using onFieldsChange and fields , see more at this rc-field-form demo. <Select style={{ width: 70 }}>
Note: Save Form data globally is not a good practice. You should avoid this if not necessary. <Option value="86">+86</Option>

<Option value="87">+87</Option>
</Select>
</[Link]>
TypeScript JavaScript
);

import React, { useState } from 'react';

import { Form, Input, Typography } from 'antd'; const suffixSelector = (

<[Link] name="suffix" noStyle>

const { Paragraph } = Typography; <Select style={{ width: 70 }}>

<Option value="USD">$</Option>

interface FieldData { <Option value="CNY">¥</Option>

name: string | number | (string | number)[]; </Select>

value?: any; </[Link]>

touched?: boolean; );

validating?: boolean;
errors?: string[]; const [autoCompleteResult, setAutoCompleteResult] = useState<string[]>([]);

}
const onWebsiteChange = (value: string) => {

interface CustomizedFormProps { if (!value) {

onChange: (fields: FieldData[]) => void; setAutoCompleteResult([]);

fields: FieldData[]; } else {

} setAutoCompleteResult(['.com', '.org', '.net'].map((domain) => `${value}${domain}`));

const CustomizedForm: [Link]<CustomizedFormProps> = ({ onChange, fields }) => ( };

<Form

name="global_state" const websiteOptions = [Link]((website) => ({

layout="inline" label: website,

fields={fields} value: website,

onFieldsChange={(_, allFields) => { }));

onChange(allFields);

}} return (

> <Form

<[Link] {...formItemLayout}

name="username" form={form}

label="Username" name="register"

rules={[{ required: true, message: 'Username is required!' }]} onFinish={onFinish}

> initialValues={{ residence: ['zhejiang', 'hangzhou', 'xihu'], prefix: '86' }}

<Input /> style={{ maxWidth: 600 }}

</[Link]> scrollToFirstError

</Form> >

); <[Link]

name="email"

const App: [Link] = () => { label="E-mail"

const [fields, setFields] = useState<FieldData[]>([{ name: ['username'], value: 'Ant Design' }]); rules={[
{

return ( type: 'email',

<> message: 'The input is not valid E-mail!',

<CustomizedForm },

fields={fields} {

onChange={(newFields) => { required: true,

setFields(newFields);

}}
/>
<Paragraph style={{ maxWidth: 440, marginTop: 24 }}>

<pre style={{ border: 'none' }}>{[Link](fields, null, 2)}</pre>


</Paragraph>

</>
);
};

export default App;

Hide

* Group Name :

User List : ( No user yet. )

Submit Add User

Control between forms

Use [Link] to process data between forms. In this case, submit button is in the Modal which is out of Form. You can use [Link] to submit form. Besides, we recommend native <Button htmlType="submit" /> to submit a form.

TypeScript JavaScript

import React, { useEffect, useRef, useState } from 'react';


import { SmileOutlined, UserOutlined } from '@ant-design/icons';

import { Avatar, Button, Form, Input, InputNumber, Modal, Space, Typography } from 'antd';
import type { FormInstance } from 'antd/es/form';

const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },

};

const tailLayout = {
wrapperCol: { offset: 8, span: 16 },
};

interface UserType {

name: string;
age: string;
}

interface ModalFormProps {
open: boolean;

onCancel: () => void;


}

// reset form fields when modal is form, closed


const useResetFormOnCloseModal = ({ form, open }: { form: FormInstance; open: boolean }) => {

const prevOpenRef = useRef<boolean>();


useEffect(() => {
[Link] = open;

}, [open]);
const prevOpen = [Link];

useEffect(() => {
if (!open && prevOpen) {

[Link]();
}
}, [form, prevOpen, open]);

};

const ModalForm: [Link]<ModalFormProps> = ({ open, onCancel }) => {


const [form] = [Link]();

useResetFormOnCloseModal({
form,

open,
});

const onOk = () => {


[Link]();
};

return (

<Modal title="Basic Drawer" open={open} onOk={onOk} onCancel={onCancel}>


<Form form={form} layout="vertical" name="userForm">
<[Link] name="name" label="User Name" rules={[{ required: true }]}>

<Input />
</[Link]>
<[Link] name="age" label="User Age" rules={[{ required: true }]}>

<InputNumber />
</[Link]>

</Form>
</Modal>
);

};

const App: [Link] = () => {


const [open, setOpen] = useState(false);

const showUserModal = () => {


setOpen(true);
};

const hideUserModal = () => {

setOpen(false);
};

const onFinish = (values: any) => {


[Link]('Finish:', values);
};

return (

<[Link]
onFormFinish={(name, { values, forms }) => {
if (name === 'userForm') {

const { basicForm } = forms;


const users = [Link]('users') || [];

[Link]({ users: [...users, values] });


setOpen(false);
}

}}
>
<Form {...layout} name="basicForm" onFinish={onFinish} style={{ maxWidth: 600 }}>

<[Link] name="group" label="Group Name" rules={[{ required: true }]}>


<Input />

</[Link]>

{/* Create a hidden field to make Form instance record this */}

<[Link] name="users" hidden />

<[Link]

label="User List"
shouldUpdate={(prevValues, curValues) => [Link] !== [Link]}

>
{({ getFieldValue }) => {
const users: UserType[] = getFieldValue('users') || [];

return [Link] ? (
<ul>
{[Link]((user) => (

<li key={[Link]} className="user">


<Space>

<Avatar icon={<UserOutlined />} />


{`${[Link]} - ${[Link]}`}
</Space>

</li>
))}

</ul>
) : (
<[Link] className="ant-form-text" type="secondary">

( <SmileOutlined /> No user yet. )


</[Link]>
);

}}
</[Link]> Hide

<[Link] {...tailLayout}>
<Button htmlType="submit" type="primary">
Submit

</Button>
<Button htmlType="button" style={{ margin: '0 8px' }} onClick={showUserModal}>
Add User

</Button>
</[Link]>

</Form>

<ModalForm open={open} onCancel={hideUserModal} />

</[Link]>
);

};

export default App;

Hide

Username Password Log in

Inline Login Form

Inline login form is often used in navigation bar.

TypeScript JavaScript

import React, { useEffect, useState } from 'react';

import { LockOutlined, UserOutlined } from '@ant-design/icons';


import { Button, Form, Input } from 'antd';

const App: [Link] = () => {


const [form] = [Link]();

const [clientReady, setClientReady] = useState<boolean>(false);

// To disable submit button at the beginning.

useEffect(() => {
setClientReady(true);

}, []);

const onFinish = (values: any) => {

[Link]('Finish:', values);
};

return (
<Form form={form} name="horizontal_login" layout="inline" onFinish={onFinish}>

<[Link]
name="username"
rules={[{ required: true, message: 'Please input your username!' }]}

>
<Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="Username" />
</[Link]>

<[Link]
name="password"

rules={[{ required: true, message: 'Please input your password!' }]}


>
<Input

prefix={<LockOutlined className="site-form-item-icon" />}


type="password"

placeholder="Password"
/>
</[Link]>

<[Link] shouldUpdate>
{() => (
<Button

type="primary"
htmlType="submit"

disabled={
!clientReady ||
![Link](true) ||

!![Link]().filter(({ errors }) => [Link]).length


}
>

Log in
</Button>

)}
</[Link]>
</Form>

);
};

export default App;

Hide

Username

Password

Remember me Forgot password

Log in
Or register now!

Login Form

Normal login form which can contain more elements.

TypeScript JavaScript CSS

import React from 'react';


import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { Button, Checkbox, Form, Input } from 'antd';

const App: [Link] = () => {

const onFinish = (values: any) => {


[Link]('Received values of form: ', values);
};

return (

<Form
name="normal_login"
className="login-form"

initialValues={{ remember: true }}


onFinish={onFinish}
>

<[Link]
name="username"

rules={[{ required: true, message: 'Please input your Username!' }]}


>
<Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="Username" />

</[Link]>
<[Link]
name="password"

rules={[{ required: true, message: 'Please input your Password!' }]}


>

<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"

placeholder="Password"
/>

</[Link]>
<[Link]>
<[Link] name="remember" valuePropName="checked" noStyle>

<Checkbox>Remember me</Checkbox>
</[Link]>

<a className="login-form-forgot" href="">


Forgot password

</a>
</[Link]>

<[Link]>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in

</Button>
Or <a href="">register now!</a>

</[Link]>
</Form>
);

};

export default App;

Hide

You might also like