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.

Usage no npm install needed!

<script type="module">
  import reactHooksUseform from 'https://cdn.skypack.dev/react-hooks-useform';
</script>

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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <TextField {...fields.phone} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <TextField {...fields.phone} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <TextField {...fields.phone} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <TextField {...fields.phone} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <SwitchField {...fields.isAdmin} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <TextField {...fields.age} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> <SelectComponent {...fields.gender} /> </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> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> </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 ( <dynamicForm.Form> <TextField {...dynamicFields.name} /> <TextField {...dynamicFields.label} /> </dynamicForm.Form> <Divider style={{ margin: '24px 16px 8px 16px' }} /> <form.Form> <TextField {...fields.fullName} /> <TextField {...fields.nickname} /> {Object.keys(fields) .filter(key => (key !== 'fullName' && key !== 'nickname')) .map(key => ( <TextField {...fields[key]} /> <Button onClick={() => form.removeField(key)}>X )) } </form.Form> ) }

export { DynamicFields }