In this blog, we will explore React Hook Form, an extremely lightweight and effective form building library using React. This open-source, third-party library has no dependencies and can be integrated with most existing forms or libraries. It provides the ability to subscribe to individual components, limiting the frequency of re-renders and making it more efficient.
Below, we will learn some of the basic usages of React Hook Form, some more in-depth features, and then look at an example form integrated with an existing UI library.
Basics
Setup
React Hook Form’s simple API makes it a more powerful tool using fewer lines of code than the average form library. The cornerstone of this library is the useForm()
hook. This custom hook manages the form states and validations. The basic usage of the useForm()
hook looks similar to a useState()
hook.
const { register, handleSubmit } = useForm();
The register()
method will register uncontrolled inputs or selects and apply the given validation rules to the field. When using register
, you must supply a unique name to identify the field inside the form. This method also accepts a set of validation rules to apply to the given input.
handleSubmit
can be called to receive the form data, given all validation has passed on all inputs in the form. Below is an example form with some basic input fields with validation.
<form onSubmit={handleSubmit(onSubmit)}> <input {...register(‘firstName’), { required: true })} /> <input {...register(middleName)} /> <input {...register(‘lastName’, { required: true })} /> <input type=’submit’ /> </form>
There are several optional arguments available for useForm()
that can help to direct the proper form behavior. A few significant ones to highlight are:
mode
: Configures the validation strategy before the user submits the form, whether it’sonSubmit
,onChange
,onTouched
, etc.
reValidateMode
: Configures the validation strategy after the user submits the form. For example, if there are validation errors present, this will specify when the form should be revalidated.
defaultValues
: Used for the initial values when the components are first rendered.
Validation
React Hook Form uses the existing HTML standard for form validation, making it painless to apply basic validation to any field. Should one of the basic operations not meet your requirements, custom validation methods can also be provided.
List of Supported Validation Rules:
required
: boolean → if true, indicates that the input must have a value before the form can be submitted
min
: number → minimum value to accept for this input
max
: number → maximum value to accept for this input
minLength
: number → minimum length of the value to accept for this input
maxLength
: number → maximum length of the value to accept for this input
pattern
: RegExp → the regex pattern for the input
validate
: function | Object → callback function or an object of callback functions to validate
Based on the form’s current mode
setting, the given validation rules will be applied to the input field at that time. After registering inputs and validations, React Hook Form will provide access to a list of errors derived from the form state. Form errors can be retrieved from the useForm()
hook by modifying it as follows.
const { register, handleSubmit, formState: { errors } } = useForm();
Once retrieved, we can utilize the results and conditionally render error messages to identify which inputs did not pass validation.
<form onSubmit={handleSubmit(onSubmit)}> <input {...register(‘firstName’), { required: true })} /> {errors.firstName && <p>This field is required.</p>} <input {...register(‘middleName’)} /> <input {...register(‘lastName’, { required: true })} /> {errors.lastName && <p>This field is required.</p>} <input type=’submit’ /> </form>
More Features
Subscribing to Input Changes
Subscribing to an input will watch the given input and return its value. This can be useful when rendering based on an input’s value. After adding watch
to the useForm()
hook, the method can be used to track an input.
const { register, handleSubmit, watch, formState: { errors } } = useForm(); const watchMiddleName = watch(‘middleName’);
This value can now be used however needed, whether that be logging or using it to decide how to render.
<form onSubmit={handleSubmit(onSubmit)}> <input {...register(‘firstName’), { required: true })} /> {errors.firstName && <p>This field is required.</p>} <input {...register(‘middleName’)} /> {watchMiddleName?.length > 0 && <p>This field is optional!</p>} <input {...register(‘lastName’, { required: true })} /> {errors.lastName && <p>This field is required.</p>} <input type=’submit’ /> </form>
Schema Validation
React Hook Form is capable of using schema-based form validation using third-party libraries such as Yup, Zod, Superstruct, and Joi. Schemas can be passed into useForm()
using the optional resolver
config property. Using Yup, the example form can be updated as shown below.
const schema = yup.object({ firstName: yup.string().required(), lastName: yup.string().required() }).required(); const { register, handleSubmit, watch, formState: { errors } } = useForm({ resolver: yupResolver(schema) });
<form onSubmit={handleSubmit(onSubmit)}> <input {...register(‘firstName’)} /> {errors.firstName && <p>This field is required.</p>} <input {...register(‘middleName’)} /> {watchMiddleName?.length > 0 && <p>This field is optional!</p>} <input {...register(‘lastName’)} /> {errors.lastName && <p>This field is required.</p>} <input type=’submit’ /> </form>
Integrating with UI Libraries
Using an existing UI library can reduce the amount of styling and component setup needed to make a form look great. UI components that do not explicitly expose the input ref can be registered using React Hook Form’s Controller
component.
This will handle registering the UI component and can be passed optional validation similar to using the register method. Below is an example using Material-UI’s TextField
component for an input while still applying validation to make the field required.
const { control, handleSubmit } = useForm(); <form onSubmit={handleSubmit(onSubmit)}> <Controller name=’firstName’ control={control} rules={{ required: true }} render={({ field }) => <TextField variant='filled' label=First name {...field} /> } /> <input type=’submit’ /> </form>
Wrap Up
Creating a reliable form can be a difficult thing to accomplish, especially when trying to handle validation and error states. Using React Hook Form makes it simpler than ever. This lightweight framework can be integrated into almost any project while making very little impact on processing and rendering.
If you wish to continue exploring React Hook Form hands-on, this repo contains a basic form with validation integrated with Material-UI. For further reading into these or more advanced topics, visit the React Hook Form documentation.
Additionally, if you’re looking for more on React, I wrote a post a couple of years ago that you might find useful. Check it out on the Keyhole Dev Blog → Storybook With React.