# Controller

> Wrapper component for integrating controlled external inputs like MUI, Chakra UI, and React-Select with React Hook Form validation.

Source: https://react-hook-form.com/docs/usecontroller/controller

## `Controller`: [ControllerProps](https://react-hook-form.com/ts#ControllerProps)

React Hook Form embraces uncontrolled components and native inputs; however, it's hard to avoid working with external controlled components such as [React-Select](https://github.com/JedWatson/react-select), [AntD](https://github.com/ant-design/ant-design) and [MUI](https://mui.com/). This wrapper component makes it easier for you to work with them.

**Note:** if you simply want to control a field's value from outside the form, it's not necessary to use `Controller`. You can simply use the [`values`](https://react-hook-form.com/docs/useform#values) option of `useForm`.

### Props

---

The following table contains information about the arguments for `Controller`.

| Name               | Type                                                               | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------ | ------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`             | [`FieldPath`](/ts#FieldPath "FieldPath type") | ✓        | Unique name of your input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `control`          | [`Control`](/ts#Control "Control type")       |          | The [`control`](https://react-hook-form.com/docs/useform/control) object is from invoking `useForm`. Optional when using `FormProvider`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `render`           | `Function`                                      | ✓        | This is a [render prop](https://legacy.reactjs.org/docs/render-props.html). A function that returns a React element and provides the ability to attach events and value into the component. This simplifies integrating with external controlled components with non-standard prop names. Provides `field` (with `onChange`, `onBlur`, `name`, `ref`, `value`), `fieldState`, and `formState` objects to the render callback.                                                                                                                                                                                                                                                                                                                                            |
| `rules`            | `Object`                                        |          | Validation rules in the same format for [`register` options](https://react-hook-form.com/docs/useform/register#options), which includes:<br/><br/>required, min, max, minLength, maxLength, pattern, validate                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `shouldUnregister` | `boolean = false`                               |          | Input will be unregistered after unmount and defaultValues will be removed as well.<br/><br/>**Note:** this prop should be avoided when using with `useFieldArray` as `unregister` function gets called after input unmount/remount and reorder.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `disabled`         | `boolean = false`                               |          | _(since v7.46.0)_ `disabled` prop will be returned from `field` prop. Controlled input will be disabled and its value will be omitted from the submission data.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `defaultValue`     | `unknown`                                       |          | **Important:** Cannot apply `undefined` to `defaultValue` or `defaultValues` at `useForm`. <ul><li>You need to either set `defaultValue` at the field level or `useForm`'s `defaultValues`. If you used <code>defaultValues</code> at <code>useForm</code>, skip using this prop.</li><li>If your form will invoke `reset` with default values, you will need to provide `useForm` with `defaultValues`.</li><li>Calling `onChange` with `undefined` is not valid. You should use `null` or the empty string as your default/cleared value instead.</li><li>If `field.value` is `undefined` on first render, the input starts out uncontrolled and React will warn when it later becomes controlled — always set `defaultValue`/`defaultValues` to avoid this.</li></ul> |
| `exact`            | `boolean = true`                                |          | _(since v7.68.0)_ This prop will enable an exact match for input name subscriptions, default to true. _(since v7.81.0)_ With `exact: true`, the field is also updated when one of its ancestor paths is set, but not when a nested child path of its value changes. See [`useController`](https://react-hook-form.com/docs/usecontroller) for details.                                                                                                                                                                                                                                                                                                                                                                                                                            |

### Return

---

The following table contains information about properties which `Controller` produces.

| Object Name                            | Name                 | Type                                        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------------------------- | -------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `field`                                | `onChange`           | `(value: any) => void` | A function which sends the input's value to the library.<br/><br/> _It should be assigned to the `onChange` prop of the input and the value should **not be `undefined`**._ <br/>This prop updates [formState](https://react-hook-form.com/docs/useform/formstate) and you should avoid manually invoking [setValue](https://react-hook-form.com/docs/useform/setvalue) or other APIs related to field updates. It accepts either a change event or a value: given an event, it reads `target.checked` for checkboxes, `target.files` for file inputs and `target.value` otherwise. Any object with a `target` property is treated as an event. |
| `field`                                | `onBlur`             | `() => void`           | A function which sends the input's onBlur event to the library. It should be assigned to the input's `onBlur` prop.                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `field`                                | `value`              | `unknown`                | The current value of the controlled component.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `field`                                | `disabled`           | `boolean`                | The disabled state of the input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `field`                                | `name`               | `string`                 | Input's name being registered.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `field`                                | `ref`                | `React.Ref`              | A ref used to connect hook form to the input. Assign `ref` to component's input ref to allow hook form to focus the error input — this only works if the target component forwards refs (`React.forwardRef`) or exposes an equivalent, like MUI's `inputRef`.                                                                                                                                                                                                                                                                                                                             |
| `fieldState`                           | `invalid`            | `boolean`                | Invalid state for current input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `fieldState`                           | `isTouched`          | `boolean`                | Touched state for current controlled input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `fieldState`                           | `isDirty`            | `boolean`                | Dirty state for current controlled input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `fieldState`                           | `isValidating`       | `boolean`                | Validating state for current controlled input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `fieldState`                           | `error`              | `object`                 | _(since v7.0.0)_ error for this specific input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| [`formState`](https://react-hook-form.com/docs/useform/formstate) | `isDirty`            | `boolean`                | Set to `true` after the user modifies any of the inputs. <ol><li>**Important:** Make sure to provide all inputs' defaultValues at the useForm level, so the library can have a single source of truth to compare whether the form is dirty.</li><li>File-type inputs will need to be managed at the app level due to the ability to cancel file selection and [FileList](https://developer.mozilla.org/en-US/docs/Web/API/FileList) object.</li></ol>                                                                                                                                     |
| `formState`                            | `dirtyFields`        | `object`                 | An object with the user-modified fields. Make sure to provide all inputs' defaultValues via useForm, so the library can compare against the `defaultValues` <ol><li>**Important:** Make sure to provide defaultValues at the useForm level, so the library can have a single source of truth to compare each field's dirtiness.</li><li>Dirty fields will **not** represent as `isDirty` formState, because dirty fields are marked field dirty at the field level rather than the entire form. If you want to determine the entire form state use `isDirty` instead.</li></ol>           |
| `formState`                            | `touchedFields`      | `object`                 | An object containing all the inputs the user has interacted with.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `formState`                            | `defaultValues`      | `object`                 | _(since v7.37.0)_ The value that was set in [useForm](https://react-hook-form.com/docs/useform)'s `defaultValues` or updated `defaultValues` via the [reset](https://react-hook-form.com/docs/useform/reset) API.                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `formState`                            | `isSubmitted`        | `boolean`                | Set to `true` after the form has been submitted. Will remain `true` until the `reset` method is invoked.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `formState`                            | `isSubmitSuccessful` | `boolean`                | Indicates that the form was successfully submitted without any runtime error.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `formState`                            | `isSubmitting`       | `boolean`                | `true` if the form is currently being submitted. `false` otherwise.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `formState`                            | `isLoading`          | `boolean`                | _(since v7.41.0)_ `true` if the form is currently loading async default values.<br/>**Important:** this prop is only applicable to async `defaultValues`                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `formState`                            | `submitCount`        | `number`                 | The number of times the form was submitted.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `formState`                            | `isValid`            | `boolean`                | Set to `true` if the form doesn't have any errors.<br/><br/>`setError` immediately forces `isValid` to `false`; this value is not itself derived from validation and will be overwritten the next time validation runs (e.g. on the next `onChange`, submit, or `trigger()` call).                                                                                                                                                                                                                                                                                                        |
| `formState`                            | `isValidating`       | `boolean`                | Set to `true` during validation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `formState`                            | `validatingFields`   | `object`                 | _(since v7.51.0)_ Captures fields that are undergoing asynchronous validation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `formState`                            | `errors`             | `object`                 | An object with field errors. There is also an [ErrorMessage](https://react-hook-form.com/docs/useformstate/errormessage) component to retrieve error messages easily.                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `formState`                            | `disabled`           | `boolean`                | _(since v7.48.0)_ Set to `true` if the form is disabled via the `disabled` prop in [`useForm`](https://react-hook-form.com/docs/useform#disabled).                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `formState`                            | `isReady`            | `boolean`                | _(since v7.56.0)_ Set to true when `formState` subscription setup is ready.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

### Examples

---

**Web**

**TS**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw)

```tsx
import ReactDatePicker from "react-datepicker"
import { TextField } from "@mui/material"
import { useForm, Controller } from "react-hook-form"

type FormValues = {
  ReactDatepicker: string
}

function App() {
  const { handleSubmit, control } = useForm<FormValues>()

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <Controller
        control={control}
        name="ReactDatepicker"
        render={({ field: { onChange, onBlur, value, ref } }) => (
          <ReactDatePicker
            onChange={onChange} // send the value to hook form
            onBlur={onBlur} // notify when the input is touched or blurred
            selected={value}
          />
        )}
      />

      <input type="submit" />
    </form>
  )
}
```

**JS**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5)

```javascript
import ReactDatePicker from "react-datepicker"
import { TextField } from "@mui/material"
import { useForm, Controller } from "react-hook-form"

function App() {
  const { handleSubmit, control } = useForm()

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <Controller
        control={control}
        name="ReactDatepicker"
        render={({ field: { onChange, onBlur, value, ref } }) => (
          <ReactDatePicker
            onChange={onChange}
            onBlur={onBlur}
            selected={value}
          />
        )}
      />

      <input type="submit" />
    </form>
  )
}
```

**React Native**

[Open in Expo Snack](https://snack.expo.io/@bluebill1049/react-hook-form-v7---controller)

```javascript
import { Text, View, TextInput, Button, Alert } from "react-native"
import { useForm, Controller } from "react-hook-form"

export default function App() {
  const {
    control,
    handleSubmit,
    formState: { errors },
  } = useForm({
    defaultValues: {
      firstName: "",
      lastName: "",
    },
  })
  const onSubmit = (data) => console.log(data)

  return (
    <View>
      <Controller
        control={control}
        rules={{
          required: true,
        }}
        render={({ field: { onChange, onBlur, value } }) => (
          <TextInput
            placeholder="First name"
            onBlur={onBlur}
            onChangeText={onChange}
            value={value}
          />
        )}
        name="firstName"
      />
      {errors.firstName && <Text>This is required.</Text>}

      <Controller
        control={control}
        rules={{
          maxLength: 100,
        }}
        render={({ field: { onChange, onBlur, value } }) => (
          <TextInput
            placeholder="Last name"
            onBlur={onBlur}
            onChangeText={onChange}
            value={value}
          />
        )}
        name="lastName"
      />

      <Button title="Submit" onPress={handleSubmit(onSubmit)} />
    </View>
  )
}
```

### Video

---

The following video showcases what's inside Controller and how it was built.

[Watch on YouTube](https://www.youtube.com/watch?v=N2UNk_UCVyA)

> **Tip**
>
> - It's important to be aware of each prop's responsibility when working with external controlled components such as MUI, AntD, and Chakra UI. `Controller` acts as a "spy" on your input by reporting and setting its value.
>   - **onChange**: send data back to hook form
>   - **onBlur**: report that the input has been interacted with (focus and blur)
>   - **value**: set up the input's initial and updated value
>   - **ref**: allow the input to be focused when there is an error
>   - **name**: give the input a unique name
>     The following CodeSandboxes demonstrate the usage:
>   - [MUI and other components](https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5)
>   - [Chakra UI components](https://codesandbox.io/s/chakra-ui-5mp8g)
> - Do not `register` input again. This component is made to take care of the registration process.
>
>   ```javascript
>   <Controller
>     name="test"
>     render={({ field }) => {
>       // return <input {...field} {...register('test')} />; ❌ double up the registration
>       return <input {...field} /> // ✅
>     }}
>   />
>   ```
>
> - Customise what value gets sent to hook form by transforming the value during `onChange`. For number inputs, map an empty input to `null` instead of `NaN`, and render `null` as an empty string. `rules` doesn't support `valueAsNumber`, so convert the value yourself.
>
>   ```javascript
>   <Controller
>     name="age"
>     render={({ field }) => (
>       <input
>         {...field}
>         type="number"
>         value={field.value ?? ""}
>         onChange={(e) =>
>           field.onChange(e.target.value === "" ? null : e.target.valueAsNumber)
>         }
>       />
>     )}
>   />
>   ```
>
> - **Focusing components that don't forward a DOM ref:** `field.ref` accepts any object with a `focus` method (and optionally `select`), so you can point it at the component's own focus API:
>
>   ```javascript
>   <DatePicker
>     {...field}
>     ref={(instance) =>
>       field.ref(instance && { focus: () => instance.focusInput() })
>     }
>   />
>   ```
>
