Extensible multistep forms for React Hook Form.
npm install react-hook-form-multistep
npm install react-hook-form-multistep
`
Check out the /examples for simple and complex (custom stepper, controlled components) usage. As a quick primer, here is a very simple example where each form takes in 1 piece of the state, updates it and writes it back to the state variable, provided the data in the form is valid.
`typescript
import { useForm } from 'react-hook-form'
import { useEffect, useState } from 'react'
import MultiStepForm from 'react-hook-form-multistep'
function App() {
const [state, setState] = useState({
name: 'joe',
age: '18',
})
return (
renderStepForm={({ handleStepSubmit, reportStepValidity }) => (
data={state}
onSubmit={handleStepSubmit((data) => setState({ ...data, ...state }))} // handleStepSubmit(data: FormOneData) => void)
reportStepValidity={reportStepValidity} // (isFormStepValid: boolean) => void
/>
)}
/>
renderStepForm={({ handleStepSubmit, reportStepValidity }) => (
data={state}
onSubmit={handleStepSubmit((data) => setState({ ...data, ...state }))}
reportStepValidity={reportStepValidity}
/>
)}
/>
)
}
// FormOne and FormTwo are simple react-hook-forms
`
Complex forms
For complex forms with deeply nested fields, and particularly ones with useFieldArray the simple setState({ ...data, ...state }) approach to saving each form step will not work. setState does a shallow merge of object properties. The snippet below is a helper which will deeply merge object properties and handles array inputs properly (i.e. overwriting the existing array with the new array in the submitted form step).
`typescript
// utility function
import mergeWith from 'lodash.mergewith'
import { type DeepPartial } from 'react-hook-form'
export default function mergeFormState(object: T, source: DeepPartial): T {
return mergeWith({}, object, source, replaceArrayOnMerge)
}
const replaceArrayOnMerge = (objValue: T, srcValue: DeepPartial) => {
if (Array.isArray(objValue)) {
return srcValue
}
}
// useage
...
data={store}
onSubmit={handleStepSubmit((data) => setState((prevStore) => mergeFormState(prevStore, data)))}
reportStepValidity={reportStepValidity}
/>
...
``