Create an input component that combines React Hook Form with MUI, react-number-format

Posted on: April 23, 2022

Introduction

I tried to create an input component that can be used universally by combining React Hook Form (v7), which has become a standard in the recent React form libraries, and various input components of MUI (v5), which is also commonly used in React projects. In the text input, it is always necessary to separate pure text (string type) input from numeric (number type) input, so based on the MUI TextField, I prepared two input components, MuiTextField and MuiNumberField, to distinguish between them. Also, since there are many situations where you want to format and display input values in numeric input parts, I also incorporated react-number-format into MuiNumberField so that you can format the input values.

Dependent version at the time of writing

  • React v18.0.0
  • MUI v5.6.2
  • React Hook Form v7.30.0
  • react-number-format v4.9.1

I'll post the final demo first. (Sorry for the Japanese sample.)

GitHub repository is below. (Commented in English.)

List of currently available parts.

From here, we will summarize the philosophy behind the interface design, the information we obtained for each library while creating this component, and the points that stuck out in the implementation.

Interfaces

Interface Overview

To introduce the interface, only the simplest template part of MuiTextField (string type text input component) is introduced. (See the GitHub repository at the beginning of this article for the completed code that actually works.) The other parts have the same interface.

The <MuiTextField> takes the entire form type as a type argument, which is always defined when using React Hook Form in TypeScript, so you can pass it as it is. If you pass the type here, it will be checked if the string passed to the name props exists as a key of the form.

Example of MuiTextField use
<MuiTextField<FormData, 'username'> name='username' control={control} rules={{ required: 'Enter your username.', maxLength: { value: 10, message: 'Enter up to 10 characters.' } }} config={{ displayErrorMessage: true }} muiProps={{ textFieldProps: { label: 'Username', fullWidth: true } }} />

Interface design philosophy

  • Since there are a lot of Props, I decided to divide them into three major groups and manage them separately. The first is the React Hook Form Props, which are the main part of this project, the second is the MUI Component Props, and the third is the Props for providing options that the component provider wants to incorporate on their own.
    • The React Hook Form Props are provided by the library as UseControllerProps. Since I want this Props to be on the top surface as an interface (not nested), I decided to make the Props of the parts I will create intersect with this type.
    • Some parts require multiple MUI Props. For example, in Autocomplete, we want to be able to pass the internal TextField props (form width, label, etc.) in addition to the props of Autocomplete itself. Since there is a high possibility of conflicts between React Hook Form's props and MUI's props, which have many of the same names (and unintentional conflicts can cause bugs), we separated them from the beginning to eliminate the possibility of creating bugs. We have eliminated the possibility of creating bugs by separating them from the beginning.
    • Props for providing options that you want to incorporate yourself are now grouped into an object and can be passed through config, just like MUI's Props. The MuiNumberField config is intersected with NumberFormatPropsBase, as I thought it would be semantically better to fit here.

(Writing...)


share on...