3 min read

Form Handling - MUI + React Hook Form


Josip Blažević




Form handling blog post banner

Forms are an essential part of most websites. They allow user to interact with the website. All the data which has been input needs to be validated and sent to the server.

React Hook Form library can help you simplify form handling in a way that you need to write less code and implement form validation easily.

Material-UI provides already styled, but still very customizable inputs, that encapsulate adding labels and error handling by adding helper texts with inputs.

Fill in the form

About React Hook Form

As one of the most basic examples which React Hook Form library documentation presents to the users is using register function from useForm hook. The example is shown below:

import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit, formState: { errors } } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input defaultValue="test" {...register("example")} /> <input {...register("exampleRequired", { required: true })} /> {errors.exampleRequired && <span>This field is required</span>} <input type="submit" /> </form> ); }

When using register function, data connected to inputs is written directly as part of the input field. This works fine with basic HTML elements in React, but some unexpected behaviors can happen when UI libraries are added.

In this blog post I will focus on using controller instead of passing register. At first glance it may seem complicated, but it can simplify coding a lot in the long run.

One of the main things about React Hook Form is just how simple using uncontrolled inputs is. Uncontrolled inputs reduce number of required rerenders which can greatly boost performance of developed website, while controller makes easy it easy to work with controlled components from UI libraries.

Things we always need from useForm hook are handleSubmit, control and errors. handleSubmit is a callback function which accepts our custom onSubmit function. Control is an internal state of React Hook Form which is passed to controllers. Errors is state which holds all input errors, with input names as object properties.

Additionally React Hook Form library provides an easy way to reset input field after submit with reset function, following current form states with watch function, trigger function for manual validation triggering (useful in multistep forms) and other.

Form validation can be implemented by passing rules in Controller. Some of the commonly used rules are:

required: { value: true, message: 'message' } validate: (value) => { if (value % 2 === 0) return true return 'Not an even number' // return String | Boolean } pattern: regex min: minimumNumber max: maximumNumber minLength: minimumLength maxLength: maxiumumLength

React Hook Form is TypeScript friendly. FormData type can be defined to ensure that form returns data of expected type.

type FormData = { firstName: string; lastName: string; }; const { register, setValue, handleSubmit, formState: { errors } } = useForm<FormData>();

Also there are many predefined types which can help you with type checking and code autocomplete about which you can read more in the official documentation.

Learn more about React Hook Form by reading documentation.

About Material-UI TextField

TextField allows users to enter data into forms and dialogs.

TextField is a wrapper component which includes form control which includes label, input and helper text.

Out of the box it supports standard, outlined and filled style variant.

Inputs do not have to be just simple inputs, they can be represented as select by passing a select prop or textarea by passing multiline prop.

Icons can be added to inputs by passing icon element as startAdornment or endAdornment as InputProps.

There are many more ways in which TextFields can be customized, about which you can learn by reading Material-UI TextField documentation.

<TextField multiline label="TextField" InputProps={{ startAdornment: ( <InputAdornment position="start"> <AccountCircle /> </InputAdornment> ), }} />

Material-UI + React
Hook Form

With Material-UI TextField input errors can be easily shown to the user by adding error and helperText properties. React Hook Form provides errors object which has properties named by input field names if errors are present.

import { Controller, useForm } from 'react-hook-form'; const { handleSubmit, control, reset, formState: { errors } } = useForm(); const onSubmit = React.useCallback((values) => { console.log(values); reset(); }, []); <form onSubmit={handleSubmit(onSubmit)}> <Controller render={({ field: { name, value, onChange } }) => ( <TextField name={name} value={value} onChange={onChange} // or shorter {...field} label={fields.firstName.label} error={Boolean(errors[fields.firstName.name])} helperText={errors[fields.firstName.name] ? errors[fields.firstName.name].message : ''} /> )} control={control} name={fields.firstName.name} defaultValue="" rules={{ required: { value: true, message: 'Invalid input' } }} /> </form>

There is a simple way to combine Material-UI TextField and React Hook Form with controller.

  • • Wrap the TextField with Controller and pass control, name of the input, default value and validation rules.
  • • TextField implements that given name, value and default of custom onChange function, label or placeholder and error state and helper text from React Hook Form error state.
  • • Form element has onSubmit callback function which call React Hook Form handleSubmit function with custom onSubmit function as argument.
  • • onSubmit callback function holds all code which needs to be executed on form submit. Parameter values hold all values from form.

This way you can easily validate forms, show messages and submit them when the input data is valid.

Contact form with error messages

Learn more about Controller on React Hook Form Controller API documentation website