Combine MUI and React hook form

MUI is a rich UI tool kit that provides a lot of components based on Material Design. However, handling forms data is out of its scope, but there is React Hook Form for it. So could we combine those features? Yes, we can inherit MUI components for it.

For example, we can create a TextField component like:

import MuiTextField, { TextFieldProps } from "@mui/material/TextField";
import { Control, Controller } from "react-hook-form";


type CustomTextFieldProps = {
  name: string;
  control: Control<any>;
} & TextFieldProps

function TextField ({
  name,
  control,
  ...props
}: CustomTextFieldProps) {
  return (
    <Controller
      render={({ field, fieldState }) => 
        <MuiTextField 
          onChange = {field.onChange} // send value to hook form
          onBlur = {field.onBlur} // notify when input is touched/blur
          value = {field.value} // input value
          name = {field.name} // set the input name
          inputRef = {field.ref} // pass the input ref to the mui text field, so we can focus on the input when error appear
          {
            ...(
              fieldState.error && {
                error: true,
                helperText: fieldState.error.message
              }
            )
          }
          {...props}
        />
      }
      name={name}
      rules={
        {...(props.required && {required: 'This field is required'})}
      }
      control={control}
      defaultValue=""
    />
  );
}

export default TextField;

It seems complicated, but it’s not. The main element is the control from React hook form, which is used for handling things such as form processing data, and validation. Then we bind the MUI Textfield and the control by using the Controller component from React hook form. Now we can tell the control what to render, in this example we are using MUI TextField. Then set the value from the control’s field to render that in the TextField, and bind the events like onChange, onBlur so that the form control can know the actions in the text field and do some validations. InputRef is used to set focus if getting any errors.

Here is a more complicated demo to show how it works, it might need a longer time to load.