react-hooks-useform
v0.1.86
Published
`react-hooks-useform` implements React hooks to enable an complete, lightweight form implementation for React. It works best with Material-UI components but can be used with native react inputs as well.
Downloads
964
Readme
react-hooks-useform
react-hooks-useform
implements React hooks to enable an complete, lightweight form implementation for React.
It works best with Material-UI components but can be used with native react inputs as well.
Installation
npm install --save react-hooks-useform
yarn add react-hooks-useform
Documentation
const [fieldProps, formProps] = useForm(formConfiguration)
formConfiguration
Prop|Type|Required|Description ----|----|--------|----------- fields|Array|Yes|Array of objects describing fieldConfiguration (see fieldConfiguration) submit|Function|Yes|(values)=>void Function calls when submit is triggered on form. validate|Function or Function[]|No| Called each time the form validates initialValues| Map<String, any>|No| Values to populate form fields. Can be lazy loaded. options|FormOptions|No|optional configurations
fieldConfiguration
Prop|Type|Required|Description
----|----|--------|-----------
name|String|Yes|Name of the field. Will be used to pull data from initialValues.
type|FieldTypes|No|Type of field data (text,boolean,select,number)
helperText|String|No|Helper/Error text associated with the field
optional|Boolean|No|Specifies if the field is optional or required for field validation
requiredMessage|String|No|Message to display when required field validation fails (Defaults to 'Required')
label|String|No|Label to display with the field
normalize|Function|No|Normlalization function during onChange event to normalize data such as numbers/phones etc.
value|any|No|Initial value used by the field (default: "")
validate|(value: T, fieldName: String, getValues: () => IValues) => String|No|Validation function for field level validation. Can be combined with Form level validation.
options|Array|No|Pass through options if type
is select
valueFromChange|(event: Object) => T|No|Helper function used if onChange handler needs to provide a value other than event.target.value
fieldProps Object
Prop|Type|Description
----|----|-----------
error|Boolean|True if error exists on field, otherwise false
helperText|String|Helper or error text
label|String|Label provided by fieldConfiguration, Formatted as ${label} (optional)
if field configured as an optional field. This can be customized in FormOptions
value|any|Controlled value of the field
onBlur|Function|Event triggered upon input blur
onChange|Function|Event triggered upon input change
formProps Object
Prop|Type|Description
----|----|-----------
Form|React.Component|Component used to wrap the form inputs
submit|Function|Function to invoke when form should be submitted. Will trigger validation and if successful, trigger formConfiguration.submit
addField|(field: fieldConfiguration) => void|Call to add a new field dynamically to the form
removeField|(fieldName: String) => void|Call to remove a field dynamically form the form
fieldConfiguration
Prop|Type|Required|Description ----|----|--------|----------- optionalLabelFormatter|(label: String) => String|No|Function invoked to format labels for fields that are configured as optional
Examples
The following examples utilize Material-UI inputs
Simple Form
const SimpleForm = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { SimpleForm }
Optional Fields
const SimpleFormOptionalFields = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname', optional: true },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { SimpleFormOptionalFields }
Customize optional field prompt
const CustomizeOptionalPrompt = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname', optional: true },
],
options: {
optionalLabelFormatter: label => `${label} - not required`,
},
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { CustomizeOptionalPrompt }
Field level validation
const FieldValidation = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname', optional: true },
{ name: 'phone', label: 'Phone', validate: validatePhone },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<TextField {...fields.phone} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { FieldValidation }
Field input normalize
const normalizePhone = input => {
let normalizedPhone
...
return normalizedPhone
}
const FieldNormalize = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname', optional: true },
{ name: 'phone', label: 'Phone', validate: validatePhone, normalize: normalizePhone },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<TextField {...fields.phone} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { FieldNormalize }
Custom helper text
const HelperText = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname', optional: true },
{ name: 'phone', label: 'Phone', helperText: 'Please enter a phone number' },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<TextField {...fields.phone} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { HelperText }
Custom required field message
const CustomRequiredMessage = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name', requiredMessage: 'Name is Required' },
{ name: 'nickname', label: 'Nickname', optional: true },
{ name: 'phone', label: 'Phone', requiredMessage: 'Phone is Required' },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<TextField {...fields.phone} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { CustomRequiredMessage }
Boolean field
const BooleanToggle = () => {
const SwitchField = ({ label, error, helperText, ...rest }) => {
return (
<FormControlLabel
control={(
<Switch
{...rest}
/>
)}
label={label}
/>
)
}
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
{ name: 'isAdmin', label: 'Administrator', type: 'boolean' },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<SwitchField {...fields.isAdmin} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { BooleanToggle }
Number field
const NumberField = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
{ name: 'age', label: 'Age', type: 'number', normalize: normalizeNumber },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<TextField {...fields.age} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { NumberField }
Select field
const SelectField = () => {
const SelectComponent = ({
label,
error,
value,
helperText,
children,
options,
...rest
}) => {
return (
<FormControl>
{label && <InputLabel error={error}>{label}</InputLabel>}
<Select
value={value}
{...rest}
error={error}
>
{options.map((option) => {
return <MenuItem key={options.value} value={option.value}>{option.label}</MenuItem>
})}
</Select>
<FormHelperText error={error}>{helperText}</FormHelperText>
</FormControl>
)
}
const genderOptions = [
{ value: 'male', label: 'Male' },
{ value: 'female', label: 'Female' },
]
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
{ name: 'gender', label: 'Gender', type: 'select', options: genderOptions },
],
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
<SelectComponent {...fields.gender} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { SelectField }
Initial values passed into form
const InitialValuesSet = ({ initialValues }) => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
],
initialValues,
})
return (
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
)
}
export { InitialValuesSet }
Dynamic fields
const DynamicFields = () => {
const [fields, form] = useForm({
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'nickname', label: 'Nickname' },
],
})
const [dynamicFields, dynamicForm] = useForm({
fields: [
{ name: 'name', label: 'Name' },
{ name: 'label', label: 'Label' },
],
submit: values => {
const name = values.get('name')
const label = values.get('label')
form.addField({ name, label })
},
})
return (
<Flexbox flexDirection='column'>
<dynamicForm.Form>
<Flexbox>
<TextField {...dynamicFields.name} />
<TextField {...dynamicFields.label} />
<Button type='submit' onClick={dynamicForm.submit}>Add Field</Button>
</Flexbox>
</dynamicForm.Form>
<Divider style={{ margin: '24px 16px 8px 16px' }} />
<form.Form>
<Flexbox flexDirection='column'>
<TextField {...fields.fullName} />
<TextField {...fields.nickname} />
{Object.keys(fields)
.filter(key => (key !== 'fullName' && key !== 'nickname'))
.map(key => (
<Flexbox key={key}>
<TextField {...fields[key]} />
<Button onClick={() => form.removeField(key)}>X</Button>
</Flexbox>
))
}
</Flexbox>
<Button type='submit' onClick={form.submit}>Submit</Button>
</form.Form>
</Flexbox>
)
}
export { DynamicFields }