# useForm

> The primary React Hook Form hook. Initialize your form with validation rules, default values, and submission handling in a single call.

Source: https://react-hook-form.com/docs/useform

Related: [register](https://react-hook-form.com/docs/useform/register) · [unregister](https://react-hook-form.com/docs/useform/unregister) · [formstate](https://react-hook-form.com/docs/useform/formstate) · [watch](https://react-hook-form.com/docs/useform/watch) · [subscribe](https://react-hook-form.com/docs/useform/subscribe) · [handlesubmit](https://react-hook-form.com/docs/useform/handlesubmit) · [reset](https://react-hook-form.com/docs/useform/reset) · [resetField](https://react-hook-form.com/docs/useform/resetfield) · [resetDefaultValues](https://react-hook-form.com/docs/useform/resetdefaultvalues) · [setError](https://react-hook-form.com/docs/useform/seterror) · [clearErrors](https://react-hook-form.com/docs/useform/clearerrors) · [setValue](https://react-hook-form.com/docs/useform/setvalue) · [setValues](https://react-hook-form.com/docs/useform/setvalues) · [setFocus](https://react-hook-form.com/docs/useform/setfocus) · [getValues](https://react-hook-form.com/docs/useform/getvalues) · [getErrors](https://react-hook-form.com/docs/useform/geterrors) · [getFieldState](https://react-hook-form.com/docs/useform/getfieldstate) · [trigger](https://react-hook-form.com/docs/useform/trigger) · [control](https://react-hook-form.com/docs/useform/control) · [Form](https://react-hook-form.com/docs/useform/form)

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

`useForm` is a custom hook for managing forms with ease. It takes one object as an **optional** argument. The following example demonstrates all of its properties along with their default values.

**Generic props:**

| Option                                                  | Description                                                                                                                                                                                           |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [mode](#mode)                                           | Validation strategy for **before** submission behavior.                                                                                                                                               |
| [reValidateMode](#reValidateMode)                       | Validation strategy for **after** submission behavior.                                                                                                                                                |
| [defaultValues](#defaultValues)                         | Default values for the form; this value will be cached.                                                                                                                                               |
| [values](#values)                                       | Reactive values to update the form values.                                                                                                                                                            |
| [errors](#errors)                                       | Server returns errors to update form. **⚠ Important:** Keep the errors object reference-stable to avoid infinite re-renders.                                                                         |
| [resetOptions](#resetOptions)                           | Option to reset form state when updating with new form values.                                                                                                                                        |
| [criteriaMode](#criteriaMode)                           | Display all validation errors or one at a time.                                                                                                                                                       |
| [shouldFocusError](#shouldFocusError)                   | Enable or disable built-in focus management.                                                                                                                                                          |
| [delayError](#delayError)                               | Delay error from appearing instantly.                                                                                                                                                                 |
| [validate](#validate)                                   | Form-level validation is limited to built-in validation methods.                                                                                                                                      |
| [shouldUseNativeValidation](#shouldUseNativeValidation) | Use browser built-in form constraint API.                                                                                                                                                             |
| [shouldUnregister](#shouldUnregister)                   | Enable and disable input unregister after unmount.                                                                                                                                                    |
| [progressive](#progressive)                             | Forward validation attributes (`required`, `min`, `max`, etc.) as native HTML attributes on inputs. Enables progressive enhancement for the `Form` component (usable HTML before hydration/JS loads). |
| [disabled](#disabled)                                   | Disable the entire form with all associated inputs.                                                                                                                                                   |
| [formControl](https://react-hook-form.com/docs/createFormControl)                  | Supply a pre-created form control object (from `createFormControl`) instead of letting `useForm` create one internally.                                                                               |

**Schema validation props:**

| Option                | Description                                               |
| --------------------- | --------------------------------------------------------- |
| [resolver](#resolver) | Integrates with your preferred schema validation library. |
| [context](#context)   | A context object to supply for your schema validation.    |

### Props

---

#### mode: `onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'` (React Native: compatible with Controller)

---

This option allows you to configure the validation strategy for before a user submits the form. Validation occurs during the `onSubmit` event, which is triggered by invoking the [`handleSubmit`](https://react-hook-form.com/docs/useform/handlesubmit) function.

| Name      | Type                        | Description                                                                                                                                                                                                              |
| --------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| onSubmit  | `string` | Validation is triggered on the `submit` event, and inputs attach `onChange` event listeners to re-validate themselves.                                                                                                   |
| onBlur    | `string` | Validation is triggered on the `blur` event.                                                                                                                                                                             |
| onChange  | `string` | Validation is triggered on the `change` event for each input, leading to multiple re-renders. Warning: this often comes with a significant impact on performance.                                                        |
| onTouched | `string` | Validation is initially triggered on the first `blur` event. After that, it is triggered on every `change` event.<br/><br/>**Note:** when using with `Controller`, make sure to wire up `onBlur` with the `render` prop. |
| all       | `string` | Validation is triggered on both `blur` and `change` events.                                                                                                                                                              |

#### reValidateMode: `onChange | onBlur | onSubmit = 'onChange'` (React Native: Custom register or using Controller)

---

This option allows you to configure the validation strategy for when inputs with errors get re-validated **after** a user submits the form (the `onSubmit` event occurs and the [`handleSubmit`](https://react-hook-form.com/docs/useform/handlesubmit) function is executed). By default, re-validation occurs during the input change event.

**Note:** _(since v7.56.0)_ Both `mode` and `reValidateMode` are reactive — you can update them after form initialization and the new strategy will take effect on subsequent validations.

#### defaultValues: `FieldValues | () => Promise<FieldValues>`

---

The `defaultValues` prop populates the entire form with default values. It supports both synchronous and asynchronous assignment of default values. While you can set an input's default value using `defaultValue` or `defaultChecked` [(as detailed in the official React documentation)](https://react.dev/reference/react-dom/components/input), it is **recommended** to use `defaultValues` for the entire form.

```javascript
useForm({
  defaultValues: {
    firstName: "",
    lastName: "",
  },
})

// set default value async
useForm({
  defaultValues: async () => fetch("/api-endpoint").then((res) => res.json()),
})
```

> **Important: Rules**
>
> - You **should avoid** providing `undefined` as a default value, as it conflicts with the default state of a controlled component.
> - `defaultValues` are cached. To reset them, use the [reset](https://react-hook-form.com/docs/useform/reset) API.
> - An async `defaultValues` function runs once, when the form mounts. If its promise rejects, `formState.isLoading` stays `true`, so catch errors inside the function and return fallback values:
>
>   ```javascript
>   useForm({
>     defaultValues: async () => {
>       try {
>         const res = await fetch("/api/user")
>         return await res.json()
>       } catch {
>         return { firstName: "", lastName: "" }
>       }
>     },
>   })
>   ```
>
> - `defaultValues` will be included in the submission result by default.
> - It's recommended to avoid using custom objects containing prototype methods, such as `Moment` or `Luxon`, as `defaultValues`.
> - There are other options for including form data:
>
>   ```javascript
>   // adding a hidden input
>   <input {...register("hidden", { value: "data" })} type="hidden" />
>   ```
>
>   ```javascript
>   // include data onSubmit
>   const onSubmit = (data) => {
>     const output = {
>       ...data,
>       others: "others",
>     }
>   }
>   ```
>

#### values: `FieldValues` _(since v7.41.0)_

---

The `values` prop will react to changes and update the form values, which is useful when your form needs to be updated by external state or server data. The `values` prop will overwrite the `defaultValues` prop, unless `resetOptions: { keepDefaultValues: true }` is also set for `useForm`.

```javascript
// set default value sync
function App({ values }) {
  useForm({
    values, // will get updated when values props updates
  })
}

function App() {
  const values = useFetch("/api")

  useForm({
    defaultValues: {
      firstName: "",
      lastName: "",
    },
    values, // will get updated once values returns
  })
}
```

> **Important: Rules**
>
> - `values` is deep-compared with the previous `values` prop. When it changes, the form is reset with the new values, which **replaces anything the user has typed**. If your data source refetches in the background (for example, React Query on window focus) and returns updated data, set `resetOptions: { keepDirtyValues: true }` to keep the user's edits.
> - Passing a new object with the same content does nothing, so you don't need to memoize `values`.
>

##### Loading form data from a server: which option to use?

| Approach                                      | Updates when the data changes                     | Good for                                                                                                                     |
| --------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Async [`defaultValues`](#defaultValues)       | No, it runs once on mount                         | Edit forms that load their data once. `formState.isLoading` is `true` until it resolves.                                     |
| [`values`](#values)                           | Yes, it resets the form whenever the data changes | Forms that must stay in sync with external or server state. Combine with [`resetOptions`](#resetOptions) to keep user edits. |
| [`reset`](https://react-hook-form.com/docs/useform/reset) in `useEffect` | Only when your effect runs                        | Full control over when the form is refilled and which state to keep.                                                         |
| Render the form after the data arrives        | No                                                | The simplest option: fetch in the parent and pass the data in as `defaultValues`.                                            |

#### errors: `FieldErrors` _(since v7.49.0)_

---

The `errors` prop will react to changes and update the server errors state, which is useful when your form needs to be updated with errors returned from the server.

```javascript
function App() {
  const { errors, data } = useFetch("/api")

  useForm({
    errors, // will get updated once errors returns
  })
}
```

#### resetOptions: [KeepStateOptions](https://react-hook-form.com/ts#KeepStateOptions) _(since v7.41.0)_

---

This property is related to value update behaviors. When `values` or `defaultValues` are updated, the `reset` API is invoked internally. It's important to specify the desired behavior after `values` or `defaultValues` are asynchronously updated. The configuration option itself is a reference to the [reset](https://react-hook-form.com/docs/useform/reset) method's options.

```javascript
// by default, an asynchronous update to values or defaultValues will reset the form values
useForm({ values })
useForm({ defaultValues: async () => await fetch() })

// options to configure the behavior
// eg: I want to keep user-interacted/dirty values and not remove any user errors
useForm({
  values,
  resetOptions: {
    keepDirtyValues: true, // user-interacted input will be retained
    keepErrors: true, // input errors will be retained with value update
  },
})
```

#### context: `object`

---

|                                                                                                                                                                   |                                                                      |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| This context `object` is mutable and will be injected into the `resolver`'s second argument or [Yup](https://github.com/jquense/yup) validation's context object. | [CodeSandbox](https://codesandbox.io/s/resolver-context-d9jqy) |

#### criteriaMode: `firstError | all`

---

|                                                                                                                                                                                          |                                                                                                         |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| <ul><li> When set to `firstError` (default), only the first error from each field will be gathered.</li> <li> When set to `all`, all errors from each field will be gathered. </li></ul> | [CodeSandbox](https://codesandbox.io/s/react-hook-form-v6-errors-validatecriteriamode-all-p9xm6) |

#### shouldFocusError: `boolean = true`

---

When set to `true` (default), and the user submits a form that fails validation, focus is set on the first field with an error.

> **note**
>
> - Only works when the field's `ref` is actually attached to a DOM element — e.g. `<input {...register('test')} />`. A custom-registered input whose returned props are never spread onto a real element (so no `ref` is attached) won't receive focus, since there's nothing to focus.
> - The focus order is based on the `register` order.
>

#### delayError: `number` _(since v7.12.0)_

---

|                                                                                                                                                                                                                        |                                                                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| This configuration delays the display of error states to the end user by a specified number of milliseconds. If the user corrects the input with errors, the error is removed instantly, and the delay is not applied. | [CodeSandbox](https://codesandbox.io/s/useform-delayerror-q6c2d) |

#### validate: `Function` _(since v7.72.0)_

---

This example demonstrates how to use the **new `validate` API** in combination with `useForm` to perform **form-level validation** in a React application.

The `validate` function receives `{ formValues, formState, eventType, name }` and must return one of: `true` (valid), a `string` (surfaced at `formState.errors.form`), or an object of `{ [fieldName]: { type, message } }` (each entry surfaced at `formState.errors.form.<fieldName>`). **Note:** `validate` does not run when a `resolver` is configured — `resolver` and `validate` are mutually exclusive, and only `resolver` runs if both are set.

##### Examples

---

```javascript
const {
  register,
  formState: { errors },
} = useForm({
  validate: async ({ formValues }) => {
    if (formValues.test1.length > formValues.test.length) {
      return {
        test: {
          type: "formError",
          message: "something is wrong here",
        },
      }
    }

    if (formValues.test === "test") {
      return "direct error message"
    }

    return true
  },
})
```

#### shouldUnregister: `boolean = false`

---

By default, an input value will be retained when an input is removed. However, you can set `shouldUnregister` to `true` to `unregister` the input during unmount.

- This is a global configuration that overrides child-level configurations. To have individual behavior, set the configuration at the component or hook level, not at `useForm`.
- By default, `shouldUnregister: false` means unmounted fields are **not validated** by built-in validation.
- By setting `shouldUnregister` to true at `useForm` level, `defaultValues` will **not** be merged against submission result.
- Setting `shouldUnregister: true` makes your form behave more closely to native forms.
  - Form values are stored within the inputs themselves.
  - Unmounting an input removes its value.
  - Hidden inputs should use the `hidden` attribute for storing hidden data.
  - Only registered inputs are included as submission data.
  - Unmounted inputs must be notified at either `useForm` or `useWatch`'s `useEffect` for the hook form to verify that the input is unmounted from the DOM.

    ```javascript
    const NotWork = ({ register, show }) => {
      // ❌ won't get notified; you need to invoke unregister
      return show && <input {...register("test")} />
    }

    const Work = ({ control, register }) => {
      // "show" is itself a registered checkbox field in the same form
      const { show } = useWatch({ control })
      // ✅ gets notified in useEffect
      return show && <input {...register("test1")} />
    }

    const App = () => {
      const [showNotWork, setShowNotWork] = useState(false)
      const { register, control } = useForm({ shouldUnregister: true })
      return (
        <div>
          <input type="checkbox" {...register("show")} />
          {/* ✅ gets notified in useForm's useEffect */}
          {showNotWork && <input {...register("test2")} />}
          <NotWork register={register} show={showNotWork} />
          <Work control={control} register={register} />
        </div>
      )
    }
    ```

#### shouldUseNativeValidation: `boolean = false` _(since v7.9.0)_

---

This config will enable [browser native validation](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation). It will also enable CSS selectors `:valid` and `:invalid`, making input styling easier. You can still use these selectors even when client-side validation is disabled.

- Only works with `onSubmit` and `onChange` modes, as the `reportValidity` execution will focus the error input.
- Each registered field's validation message must be a string to be displayed natively.
- This feature only works with the `register` API and&nbsp; `useController/Controller` that are connected with actual DOM references.
- `shouldUseNativeValidation` works independently of `progressive` — it drives the browser's Constraint Validation API (`setCustomValidity`/`reportValidity`) directly from React Hook Form's own computed validation results, regardless of whether validation attributes are forwarded as native HTML attributes. Pair it with [`progressive`](#progressive) if you also want the constraint attributes themselves (`required`, `minLength`, etc.) present on the DOM, e.g. for SSR or pre-hydration fallback validation.

  ```javascript
  useForm({
    shouldUseNativeValidation: true,
  })
  ```

##### Examples

---

```javascript
import { useForm } from "react-hook-form"

export default function App() {
  const { register, handleSubmit } = useForm({
    shouldUseNativeValidation: true,
    progressive: true,
  })
  const onSubmit = async (data) => {
    console.log(data)
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("firstName", {
          required: "Please enter your first name.",
        })} // custom message
      />
      <input type="submit" />
    </form>
  )
}
```

#### progressive: `boolean = false` _(since v7.44.0)_

---

Forwards validation rules (`required`, `min`, `max`, `minLength`, `maxLength`, `pattern`) from [`register`](https://react-hook-form.com/docs/useform/register) as native HTML attributes on the input. Enables progressive enhancement for the [`Form`](https://react-hook-form.com/docs/useform/form) component (rendering usable HTML before hydration). Independent of [`shouldUseNativeValidation`](#shouldUseNativeValidation), which drives the browser's Constraint Validation API from React Hook Form's own validation results regardless of this option — pair the two if you also want the constraint attributes present on the DOM.

```javascript
useForm({
  progressive: true,
})
```

#### disabled: `boolean = false` _(since v7.48.0)_

---

This config allows you to disable the entire form and all associated inputs when set to `true`.<br />
This can be useful for preventing user interaction during asynchronous tasks or other
situations where inputs should be temporarily unresponsive.

##### Examples

---

```javascript
import { useForm, Controller } from "react-hook-form"

const App = () => {
  const [disabled, setDisabled] = useState(false)
  const { register, handleSubmit, control } = useForm({
    disabled,
  })

  return (
    <form
      onSubmit={handleSubmit(async () => {
        setDisabled(true)
        await sleep(100)
        setDisabled(false)
      })}
    >
      <input
        type={"checkbox"}
        {...register("checkbox")}
        data-testid={"checkbox"}
      />
      <select {...register("select")} data-testid={"select"} />

      <Controller
        control={control}
        render={({ field }) => <input disabled={field.disabled} />}
        name="test"
      />

      <button type="submit">Submit</button>
    </form>
  )
}
```

#### resolver: [Resolver](https://react-hook-form.com/ts#Resolver)

---

This function allows you to use any external validation library such as [Yup](https://github.com/jquense/yup), [Zod](https://github.com/vriad/zod), [Joi](https://github.com/hapijs/joi), [Vest](https://github.com/ealush/vest), [Ajv](https://github.com/ajv-validator/ajv) and many others. The goal is to make sure you can seamlessly integrate whichever validation library you prefer. If you're not using a library, you can always write your own logic to validate your forms.

```bash
npm install @hookform/resolvers
```

##### Props

---

| Name      | Type                                                                                                                      | Description                                                                                                                                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `values`  | `object`                                                                                               | This object contains the entire form values.                                                                                                |
| `context` | `object`                                                                                               | This is the `context` object which you can provide to the `useForm` config. It is a mutable `object` that can be changed on each re-render. |
| `options` | <pre>{JSON.stringify({ criteriaMode: "string", fields: "object", names: "string[]" }, null,2)}</pre> | This is the options object containing information about the validated fields, names and `criteriaMode` from `useForm`.                      |

> **Important: Rules**
>
> - Schema validation focuses on field-level error reporting. Parent-level error checking is limited to the direct parent level, which is applicable for components such as group checkboxes.
> - This function will be cached.
> - Re-validation of an input will only occur one field at a time during a user’s interaction. The library itself will evaluate the `error` object to trigger re-renders accordingly.
> - A resolver cannot be used with the built-in validators (e.g.: required, min, etc.)
> - When building a custom resolver:
>   - Make sure that you return an object with both `values` and `errors` properties. Their default values should be an empty object. For example: `{}`.
>   - The keys of the `errors` object should match the `name` values of your fields, but they _must_ be hierarchical rather than a single key for deep errors:
>     `❌ { "participants.1.name": someErr }` will not set or clear properly - instead, use `✅ { participants: [null, { name: someErr } ] }` as this is reachable
>     as `errors.participants[1].name` - you can still prepare your errors using flat keys, and then use a function like this one from the zod resolver:
>     [toNestErrors(flatErrs, resolverOptions)](https://github.com/react-hook-form/resolvers/blob/master/src/toNestErrors.ts)
>

##### Examples

---

**Yup**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-apply-validation-ts-forked-nmbyh)

```tsx
import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"

const schema = yup
  .object()
  .shape({
    name: yup.string().required(),
    age: yup.number().required(),
  })
  .required()

const App = () => {
  const { register, handleSubmit } = useForm({
    resolver: yupResolver(schema), // yup, joi and even your own.
  })

  return (
    <form onSubmit={handleSubmit((d) => console.log(d))}>
      <input {...register("name")} />
      <input type="number" {...register("age")} />
      <input type="submit" />
    </form>
  )
}
```

**Zod**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-zod-resolver-ts-example-forked-w72vp)

```tsx
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

type Schema = z.infer<typeof schema>

const App = () => {
  const { register, handleSubmit } = useForm({
    resolver: zodResolver(schema),
  })

  return (
    <form
      onSubmit={handleSubmit((data) => {
        // handle inputs
        console.log(data)
      })}
    >
      <input {...register("name")} />
      <input {...register("age", { valueAsNumber: true })} type="number" />
      <input type="submit" />
    </form>
  )
}
```

**Joi**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-joiresolver-v6-ts-forked-5pseh)

```tsx
import { useForm } from "react-hook-form"
import { joiResolver } from "@hookform/resolvers/joi"
import Joi from "joi"

interface IFormInput {
  name: string
  age: number
}

const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().required(),
})

const App = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<IFormInput>({
    resolver: joiResolver(schema),
  })
  const onSubmit = (data: IFormInput) => {
    console.log(data)
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name")} />
      <input type="number" {...register("age")} />
      <input type="submit" />
    </form>
  )
}
```

**Ajv**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-ajvresolver-vr3imc)

```tsx
import { useForm } from "react-hook-form"
import { ajvResolver } from "@hookform/resolvers/ajv"

// must use `minLength: 1` to implement required field
const schema = {
  type: "object",
  properties: {
    username: {
      type: "string",
      minLength: 1,
      errorMessage: { minLength: "username field is required" },
    },
    password: {
      type: "string",
      minLength: 1,
      errorMessage: { minLength: "password field is required" },
    },
  },
  required: ["username", "password"],
  additionalProperties: false,
}

const App = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: ajvResolver(schema),
  })

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <input {...register("username")} />
      {errors.username && <p>{errors.username.message}</p>}
      <input {...register("password")} />
      {errors.password && <p>{errors.password.message}</p>}
      <button type="submit">submit</button>
    </form>
  )
}
```

**Vest**

[Open in CodeSandbox](https://codesandbox.io/s/vest-8q874)

```tsx
import { useForm } from "react-hook-form"
import { vestResolver } from "@hookform/resolvers/vest"
import vest, { test, enforce } from "vest"

const validationSuite = vest.create((data = {}) => {
  test("username", "Username is required", () => {
    enforce(data.username).isNotEmpty()
  })

  test("username", "Must be longer than 3 chars", () => {
    enforce(data.username).longerThan(3)
  })

  test("password", "Password is required", () => {
    enforce(data.password).isNotEmpty()
  })

  test("password", "Password must be at least 5 chars", () => {
    enforce(data.password).longerThanOrEquals(5)
  })

  test("password", "Password must contain a digit", () => {
    enforce(data.password).matches(/[0-9]/)
  })

  test("password", "Password must contain a symbol", () => {
    enforce(data.password).matches(/[^A-Za-z0-9]/)
  })
})

const App = () => {
  const { register, handleSubmit } = useForm({
    resolver: vestResolver(validationSuite),
  })

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <input {...register("username")} />
      <input {...register("password")} />
      <input type="submit" />
    </form>
  )
}
```

**Custom**

[Open in CodeSandbox](https://codesandbox.io/s/react-hook-form-customresoliver-ts-v7-juc63)

```tsx
import { useForm } from "react-hook-form"
import * as Joi from "joi"

interface IFormInputs {
  username: string
}

const validationSchema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),
})

const App = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<IFormInputs>({
    resolver: async (data) => {
      const { error, value: values } = validationSchema.validate(data, {
        abortEarly: false,
      })

      return {
        values: error ? {} : values,
        errors: error
          ? error.details.reduce((previous, currentError) => {
              return {
                ...previous,
                [currentError.path[0]]: currentError,
              }
            }, {})
          : {},
      }
    },
  })

  const onSubmit = (data: IFormInputs) => console.log(data)

  return (
    <div className="App">
      <h1>resolver</h1>

      <form onSubmit={handleSubmit(onSubmit)}>
        <label>Username</label>
        <input {...register("username")} />
        {errors.username && <p>{errors.username.message}</p>}
        <input type="submit" />
      </form>
    </div>
  )
}
```

Need more? See [Resolver Documentation](https://github.com/react-hook-form/resolvers#quickstart)

> **Tip**
>
> You can debug your schema via the following code snippet:
>
> ```javascript
> resolver: async (data, context, options) => {
>   // you can debug your validation schema here
>   console.log("formData", data)
>   console.log(
>     "validation result",
>     await anyResolver(schema)(data, context, options)
>   )
>   return anyResolver(schema)(data, context, options)
> }
> ```
>

#### `useForm` return and `useEffect` dependencies

In a future major release, the `useForm` return value will be memoized to optimize performance and reflect changes in the `formState`. Once that ships, the returned object will get a new reference whenever `formState` updates — so depending on it directly in a `useEffect` dependency array will re-run that effect on every `formState` change, which can create an infinite loop if the effect itself updates the form (e.g. calling `reset`).

> **Warning**
>
> Avoid depending on the entire `useForm` return value going forward — the following pattern will break once memoization ships:
>
> ```javascript
> const methods = useForm()
> 
> useEffect(() => {
>   methods.reset({ ... })
> }, [methods])
> ```
>

Passing only the relevant methods, as shown below, should avoid this kind of issue:

```javascript
const methods = useForm()

useEffect(() => {
  methods.reset({ ... })
}, [methods.reset])
```

> **Tip**
>
> The recommended way is to pass destructured methods to the dependencies of a `useEffect`
>
> ```javascript
> const { reset } = useForm()
> 
> useEffect(() => {
>   reset({ ... })
> }, [reset])
> ```
>

[More info can be found on this issue](https://github.com/react-hook-form/react-hook-form/issues/12463)

#### Return

---

The following list contains references to `useForm` return props.

- [register](https://react-hook-form.com/docs/useform/register)
- [unregister](https://react-hook-form.com/docs/useform/unregister)
- [formState](https://react-hook-form.com/docs/useform/formstate)
- [watch](https://react-hook-form.com/docs/useform/watch)
- [subscribe](https://react-hook-form.com/docs/useform/subscribe)
- [handleSubmit](https://react-hook-form.com/docs/useform/handlesubmit)
- [reset](https://react-hook-form.com/docs/useform/reset)
- [resetField](https://react-hook-form.com/docs/useform/resetfield)
- [resetDefaultValues](https://react-hook-form.com/docs/useform/resetdefaultvalues)
- [setError](https://react-hook-form.com/docs/useform/seterror)
- [clearErrors](https://react-hook-form.com/docs/useform/clearerrors)
- [setValue](https://react-hook-form.com/docs/useform/setvalue)
- [setValues](https://react-hook-form.com/docs/useform/setvalues)
- [setFocus](https://react-hook-form.com/docs/useform/setfocus)
- [getValues](https://react-hook-form.com/docs/useform/getvalues)
- [getErrors](https://react-hook-form.com/docs/useform/geterrors)
- [getFieldState](https://react-hook-form.com/docs/useform/getfieldstate)
- [trigger](https://react-hook-form.com/docs/useform/trigger)
- [control](https://react-hook-form.com/docs/useform/control)
- [Form](https://react-hook-form.com/docs/useform/form)

### Tips

---

- Give every field a default value in `defaultValues`, even if it is just `""`. `isDirty`, `dirtyFields`, `reset`, and controlled components all compare against `defaultValues`, so a missing default can make a field look dirty or switch from uncontrolled to controlled.
- If you are not sure which `mode` to use, try `mode: "onTouched"`. Errors show after the user leaves a field, and then update on every change. Users are not shown errors while they are still typing for the first time.
- To load data from an API, pass it to [`values`](#values) instead of calling `reset` in a `useEffect`. The form updates when the values change, and the values are compared deeply, so a new object with the same content does not reset the form.
- In a large form, keep `useForm` in the parent and move the parts that change often into child components. Read values with [`useWatch`](https://react-hook-form.com/docs/usewatch) and state with [`useFormState`](https://react-hook-form.com/docs/useformstate) in those children, so the whole form does not re-render on every key press.
