Form & Form Item
Basic Usage
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]return (<CForm><CFormItem label="Name"><CInputvalue={formData.name}onChange={v => setField('name', v)}/></CFormItem><CFormItem label="Gender"><CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/></CFormItem><CFormItem label="Birthday"><CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/></CFormItem><CFormItem label="Industry"><CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/></CFormItem></CForm>)}
Config Items
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const items = [{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return <CForm items={items} />}
Sizes
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const sizes = ['xs', 'sm', 'md', 'lg', 'xl']const [size, setSize] = useState('md')const items = [{label: 'Size',col: 12,children: (<CRadioGroupvalue={size}onChange={setSize}options={sizes.map(s => ({ label: s, value: s }))}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}size={size}/>)}
Gutter Sizes
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const sizes = ['xs', 'sm', 'md', 'lg', 'xl']const [gutterSize, setGutterSize] = useState('md')const items = [{label: 'Gutter Size',col: 12,children: (<CRadioGroupvalue={gutterSize}onChange={setGutterSize}options={sizes.map(s => ({ label: s, value: s }))}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}gutterSize={gutterSize}/>)}
Cols
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const [col, setCol] = useState(6)const items = [{label: 'Item Col',children: (<CRadioGroupvalue={col}onChange={setCol}options={[6, 12].map(s => ({ label: s, value: s }))}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}col={col}/>)}
Label Width
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const [labelWidth, setLabelWidth] = useState('80px')const items = [{label: 'Label Width',col: 12,children: (<CRadioGroupvalue={labelWidth}onChange={setLabelWidth}options={[{ label: '80px', value: '80px' },{ label: '100px', value: '100px' },{ label: '120px', value: '120px' },]}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}labelWidth={labelWidth}/>)}
Label Direction
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const directions = ['row', 'row-reverse', 'column', 'column-reverse']const [labelDirection, setLabelDirection] = useState('row')const items = [{label: 'Label Direction',col: 12,children: (<CRadioGroupvalue={labelDirection}onChange={setLabelDirection}options={directions.map(d => ({label: d,value: d,}))}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}labelDirection={labelDirection}/>)}
Label Align
function Demo() {const [formData, setFormData] = useState({name: 'Micheal Jackson',gender: 'male',birthday: new Date('August 29, 1958'),displayBirthday: 'August 29, 1958',industry: 'Entertainment',})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const [labelAlign, setLabelAlign] = useState('left')const items = [{label: 'Label Align',children: (<CRadioGroupvalue={labelAlign}onChange={setLabelAlign}options={['left', 'center', 'right'].map(d => ({label: d,value: d,}))}/>),},{label: 'Name',children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},]return (<CFormitems={items}labelAlign={labelAlign}/>)}
Form Validation
The form validation of Casual UI,need to used with field
rules
of CFOrmItem.
rules
is the validators. Each validator is a function that accept current value. And it need return false | string | Promise<false | string>
.
The meaning of this return:
false
means validation passed.string
means validation failed and it's the error messagePromise
means a async validation and the result is the same with above
For example. This is a validator for some field is required.
const rule = v => (v ? false : 'This field is required')
It's async validator would be like this:
const asyncRule = v =>
new Promise(resolve => {
setTimeout(() => {
resolve(v ? false : 'This field is required')
}, 1000)
})
Normal Validation
function Demo() {const [formData, setFormData] = useState({name: '',gender: '',birthday: null,displayBirthday: '',industry: '',hobbies: [],})const [validating, setValidating] = useState(false)const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const items = [{label: 'Name',field: 'name',rules: [v => (v ? false : 'Please enter Name')],children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}placeholder="Please enter Name"/>),},{label: 'Gender',field: 'gender',rules: [v => {return v === 'male' ? false : 'Can only be Male!'},],children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',field: 'birthday',rules: [v => (!v ? ' Please select Birthday' : false)],children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}placeholder=" Please select Birthday"onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',field: 'industry',rules: [v =>v !== 'IT' && v !== 'Entertainment'? 'Can only be IT or Entertainment!': false,],children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},{label: 'Hobbies',field: 'hobbies',rules: [v => (v && v.length < 2 ? 'At lease two hobbies' : false)],children: (<CCheckboxGroupvalue={formData.hobbies}onChange={v => setField('hobbies', v)}options={['Reading', 'Writing', 'Singing', 'Dancing'].map(h => ({label: h,value: h,}))}/>),},]const formRef = useRef(null)return (<div className="c-pa-md"><CFormref={formRef}value={formData}items={items}validating={validating}onValidatingChange={setValidating}/><div className="c-mt-xl"><SpaceItems><CButtonoutlinedlabel="Reset"onClick={() => formRef.current.clearAll()}/><CButtonlabel="Submit"onClick={() => formRef.current.validateAll()}/></SpaceItems></div></div>)}
Async Validation
function Demo() {const [formData, setFormData] = useState({name: '',gender: '',birthday: null,displayBirthday: '',industry: '',hobbies: [],})const [validating, setValidating] = useState(false)const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const items = [{label: 'Name',field: 'name',rules: [v => (v ? false : 'Please enter Name')],children: (<CInputvalue={formData.name}onChange={v => setField('name', v)}placeholder="Please enter Name"/>),},{label: 'Gender',field: 'gender',rules: [v => {return v === 'male' ? false : 'Can only be Male!'},],children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',field: 'birthday',rules: [v => (!v ? ' Please select Birthday' : false)],children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}placeholder=" Please select Birthday"onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',field: 'industry',rules: [v =>v !== 'IT' && v !== 'Entertainment'? 'Can only be IT or Entertainment!': false,],children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},{label: 'Hobbies',field: 'hobbies',rules: [v =>new Promise(resolve => {setTimeout(() => {resolve(v.length >= 2 ? false : 'At least two hobbies')}, 3000)}),],children: (<CCheckboxGroupvalue={formData.hobbies}onChange={v => setField('hobbies', v)}options={['Reading', 'Writing', 'Singing', 'Dancing'].map(h => ({label: h,value: h,}))}/>),},]const formRef = useRef(null)return (<div className="c-pa-md"><CFormref={formRef}value={formData}items={items}validating={validating}onValidatingChange={setValidating}/><div className="c-mt-xl"><SpaceItems><CButtonoutlinedlabel="Reset"onClick={() => formRef.current.clearAll()}/><CButtonlabel="Submit"onClick={() => formRef.current.validateAll()}/></SpaceItems></div></div>)}
Customize Form Component
Each form component can be a built-in component like CInput
, CRadioGroup
, CCheckboxGroup
, CSelect
, CDatePicker
.
It can also be some component written by yourself.
You can write a component with these props: validateCurrent, clearCurrent, hasError
, which means:
validateCurrent
:Validate current field.clearCurrent
:Clear current field.hasError
:Determine whether the current field has error or not. It is astring
orfalse
.
For example. This is a custom input component
const CustomInput = ({ validateCurrent, clearCurrent, hasError }) => (
<input
value={formData.name}
onFocus={clearCurrent}
onBlur={validateCurrent}
onChange={e => setField('name', e.target.value)}
style={{
borderColor: hasError ? 'red' : 'inherit',
}}
/>
)
function Demo() {const [formData, setFormData] = useState({name: '',gender: '',birthday: null,displayBirthday: '',industry: '',hobbies: [],})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const items = [{label: 'Name',field: 'name',rules: [v => (v ? false : 'Please enter Name')],children: ({ validateCurrent, clearCurrent, hasError }) => (<inputvalue={formData.name}onFocus={clearCurrent}onBlur={validateCurrent}onChange={e => setField('name', e.target.value)}style={{borderColor: hasError ? 'red' : 'inherit',}}/>),},{label: 'Gender',field: 'gender',rules: [v => {return v === 'male' ? false : 'Can only be Male!'},],children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',field: 'birthday',rules: [v => (!v ? ' Please select Birthday' : false)],children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}placeholder=" Please select Birthday"onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',field: 'industry',rules: [v =>v !== 'IT' && v !== 'Entertainment'? 'Can only be IT or Entertainment!': false,],children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},{label: 'Hobbies',field: 'hobbies',rules: [v => (v && v.length < 2 ? 'At least two hobbies' : false)],children: (<CCheckboxGroupvalue={formData.hobbies}onChange={v => setField('hobbies', v)}options={['Reading', 'Writing', 'Singing', 'Dancing'].map(h => ({label: h,value: h,}))}/>),},]const formRef = useRef(null)return (<div className="c-pa-md"><CFormref={formRef}value={formData}items={items}/><div className="c-mt-xl"><SpaceItems><CButtonoutlinedlabel="Reset"onClick={() => formRef.current.clearAll()}/><CButtonlabel="Submit"onClick={() => formRef.current.validateAll()}/></SpaceItems></div></div>)}
Custom Component With Hooks
You can also use hook function: useFormItemContext
which will return validateCurrent
、clearCurrent
、hasError
Use with this your custom component would be like this:
const CustomInput = ({ value, onChange }) => {
const { clearCurrent, validateCurrent, hasError } = useFormItemContext()
return (
<input
value={value}
onFocus={clearCurrent}
onBlur={validateCurrent}
onChange={e => onChange(e.target.value)}
style={{
borderColor: hasError ? 'red' : 'inherit',
}}
/>
)
}
function Demo() {// This is a custom input componentconst CustomInput = ({ value, onChange }) => {const { clearCurrent, validateCurrent, hasError } = useFormItemContext()return (<inputvalue={value}onFocus={clearCurrent}onBlur={validateCurrent}onChange={e => onChange(e.target.value)}style={{borderColor: hasError ? 'red' : 'inherit',}}/>)}const [formData, setFormData] = useState({name: '',gender: '',birthday: null,displayBirthday: '',industry: '',hobbies: [],})const setField = (k, v) =>setFormData({...formData,[k]: v,})const genderOptions = [{ label: 'Male', value: 'male' },{ label: 'Female', value: 'female' },]const industryOptions = [{ label: 'IT', value: 'IT' },{ label: 'Medical', value: 'Medical' },{ label: 'Entertainment', value: 'Entertainment' },{ label: 'Transportation', value: 'Transportation' },]const items = [{label: 'Name',field: 'name',rules: [v => (v ? false : 'Please enter Name')],children: (<CustomInputvalue={formData.name}onChange={v => setField('name', v)}/>),},{label: 'Gender',field: 'gender',rules: [v => {return v === 'male' ? false : 'Can only be Male!'},],children: (<CRadioGroupvalue={formData.gender}options={genderOptions}onChange={v => setField('gender', v)}/>),},{label: 'Birthday',field: 'birthday',rules: [v => (!v ? ' Please select Birthday' : false)],children: (<CDatePickerformat="MMM DD, YYYY"value={formData.birthday}placeholder=" Please select Birthday"onChange={v => setField('birthday', v)}formattedValue={formData.displayBirthday}onFormattedValueChange={v => setField('displayBirthday', v)}/>),},{label: 'Industry',field: 'industry',rules: [v =>v !== 'IT' && v !== 'Entertainment'? 'Can only be IT or Entertainment!': false,],children: (<CSelectvalue={formData.industry}onChange={v => setField('industry', v)}options={industryOptions}/>),},{label: 'Hobbies',field: 'hobbies',rules: [v => (v && v.length < 2 ? 'At least two hobbies' : false)],children: (<CCheckboxGroupvalue={formData.hobbies}onChange={v => setField('hobbies', v)}options={['Reading', 'Writing', 'Singing', 'Dancing'].map(h => ({label: h,value: h,}))}/>),},]const formRef = useRef(null)return (<div className="c-pa-md"><CFormref={formRef}value={formData}items={items}/><div className="c-mt-xl"><SpaceItems><CButtonoutlinedlabel="Reset"onClick={() => formRef.current.clearAll()}/><CButtonlabel="Submit"onClick={() => formRef.current.validateAll()}/></SpaceItems></div></div>)}
All the form item's props which has the same name with form will override the form's value.
It's useful when you want to a special item to have different styles.
CForm Props
Name (*for required) | Description | Type | Default Value |
---|
CFormItem Props
Name (*for required) | Description | Type | Default Value |
---|