Search code examples
reactjsmaterial-uirefreact-hook-form

How to use Material UI Select with react-hook-form?


I've built a form in React using Material UI and React Hook Form. I'm trying to create a custom TextField element that works as a Select Input. I would like it to be an uncontrolled component with a Ref prop. I've tried to pass the inputRef prop as the Material UI and React Hook Form docs recommend but with no success.

            <TextField
              id="id"
              name="name"
              select
              native="true"
              className={classes.textField}
              label="label"
              margin="normal"
              variant="outlined"
              inputRef={register({ required: "Choose one option" })}
              error={!!errors.name}
            >
              <MenuItem value="">Choose one option</MenuItem>
              <MenuItem value="3">03</MenuItem>
              <MenuItem value="6">06</MenuItem>
              <MenuItem value="9">09</MenuItem>
              <MenuItem value="12">12</MenuItem>
              <MenuItem value="16">16</MenuItem>
              <MenuItem value="18">18</MenuItem>
            </TextField>

One thing that I've found is that if I use the native select with ref, it works just fine.

Besides, I tried to change the inputRef prop to a SelectProps one but it didn't work too.


Solution

  • Using Select component from Material UI with react hook form need you to implement custom logic with a Controller https://react-hook-form.com/api#Controller

    Here is a reusable component that will hopefully simplify the code to use that Select component in your app:

    import React from "react";
    import FormControl from "@material-ui/core/FormControl";
    import InputLabel from "@material-ui/core/InputLabel";
    import Select from "@material-ui/core/Select";
    import { Controller } from "react-hook-form";
    
    const ReactHookFormSelect = ({
      name,
      label,
      control,
      defaultValue,
      children,
      ...props
    }) => {
      const labelId = `${name}-label`;
      return (
        <FormControl {...props}>
          <InputLabel id={labelId}>{label}</InputLabel>
          <Controller
            as={
              <Select labelId={labelId} label={label}>
                {children}
              </Select>
            }
            name={name}
            control={control}
            defaultValue={defaultValue}
          />
        </FormControl>
      );
    };
    export default ReactHookFormSelect;
    

    You can use it in your app like this:

               <ReactHookFormSelect
                  id="numero_prestacao"
                  name="numero_prestacao"
                  className={classes.textField}
                  label="Em quantas parcelas?"
                  control={control}
                  defaultValue={numero_prestacao || ""}
                  variant="outlined"
                  margin="normal"
                >
                  <MenuItem value="">Escolha uma opção</MenuItem>
                  <MenuItem value="3">03 parcelas</MenuItem>
                  <MenuItem value="6">06 parcelas</MenuItem>
                  <MenuItem value="9">09 parcelas</MenuItem>
                  <MenuItem value="12">12 parcelas</MenuItem>
                  <MenuItem value="16">16 parcelas</MenuItem>
                  <MenuItem value="18">18 parcelas</MenuItem>
                </ReactHookFormSelect>
    

    Here is your codeSandBox updated with this component for the selects in the Information form:

    https://codesandbox.io/s/unit-multi-step-form-kgic4?file=/src/Register/Information.jsx:4406-5238