Skip to content

FAQs

frequently asked questions

Performance of React Hook Form

Performance is one of the primary reasons why this library was created. React Hook Form relies on uncontrolled components, which is the reason why the register function occurs at the ref. This approach reduces the amount of re-rendering that occurs due to a user typing in an input or other form values changing. Components mount to the page faster than controlled components because they have less overhead. As a reference, there is a quick comparison test that you can refer to at this repo link.


How to create an accessible input error and message?

React Hook Form is based on Uncontrolled Components, which gives you the ability to build an accessible custom form easily.

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type="text"
        aria-invalid={errors.firstName ? "true" : "false"}
        name="firstName"
        ref={register({ required: true })}
      />
      { errors.firstName && (
          <span role="alert">
            This field is required
          </span>
        )
      }

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

Does it work with Class Components?

No, not out of the box. If you wanted to do this, you could build a wrapper around it and use it in your Class Component.

You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.

How to reset the form?

There are two methods to clear the form:

  • HTMLFormElement.reset()

    This method does the same thing as clicking a form's reset button, and only clears input/select/checkbox values.

  • React Hook Form API: reset()

    React Hook Form's reset method will reset all field values, and will also clear all errors within the form.


How to initialize form values?

Being that React Hook Form relies on uncontrolled components, you can specify a defaultValue or defaultChecked to an individual field. However, it is more common to initialize a form by passing defaultValues to useForm.

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm({
    defaultValues: {
      firstName: "bill",
      lastName: "luo",
      email: "bluebill1049@hotmail.com"
    }
  });
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <input name="lastName" ref={register} />
      <input name="email" ref={register} />

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

How to share ref usage?

React Hook Form needs a ref to collect the input value, however, you may want to use ref for other purposes (e.g. scroll into the view, or focus).

import React, { useRef } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}import React, { useRef } from "react";
import { useForm } from "react-hook-form";

type Inputs = {
  firstName: string,
  lastName: string,
};

export default function App() {
  const { register, handleSubmit } = useForm<Inputs>();
  const firstNameRef = useRef<HTMLInputElement | null>(null);
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}

What if you don't have access to ref?

You can actually register an input without a ref. In fact, you can manually setValue, setError and trigger.

Note: Because ref has not been registered, React Hook Form won't be able to register event listeners to the inputs. This means you will have to manually update value and error.

import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, setValue, setError } = useForm();
  const onSubmit = data => console.log(data);

  useEffect(() => {
    register({ name: "firstName" }, { required: true });
    register({ name: "lastName" });
  }, []);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        name="firstName"
        onChange={e => setValue("firstName", e.target.value)}
      />
      <input
        name="lastName"
        onChange={e => {
          const value = e.target.value;
          if (value === "test") {
            setError("lastName", "notMatch")
          } else {
            setValue("lastName", e.target.value)
          }
        }}
      />
      <button>Submit</button>
    </form>
  );
}

Browser Support?

React Hook Form supports all major browsers.

For legacy IE11 support, you can import react-hook-form IE 11 version.

import { useForm } from 'react-hook-form/dist/index.ie11'; // V6
import { useForm } from 'react-hook-form/dist/react-hook-form.ie11'; // V5'

If you encounter:

Object doesn't support property or method 'find'

You should try to add this find polyfill to the top of your app.js


Why is first keystroke is not working?

Double check if you are using value instead of defaultValue.

React Hook Form is based on uncontrolled inputs, which means you don't need to change the input value via state via onChange. This means you don't need value at all, and in fact, you only need to set defaultValue for the initial input value.


Testing failed due to MutationObserver?

If you have difficulty during testing and the issue was caused by MutationObserver. Make sure you install mutationobserver and import this package in your test setup.js file.

npm i mutationobserver-shim

React Hook Form, Formik or Redux Form?

First of all, all libs try to solve the same problem: make the form building experience as easy as possible. However, there are some fundamental differences between the three. react-hook-form is built with uncontrolled inputs in mind and tries to provide your form with the best performance and least amount of re-renders as possible. On top of that,react-hook-form is built with React Hooks and used as a hook, which means there is no Component for you to import. Here are some of the detail differences:

React Hook Form

Formik

Redux Form

Componentuncontrolled & controlledcontrolledcontrolled
Renderingminimum re-renderre-render according to local state changes which means as you type in the input.re-render according to state management lib (Redux) changes which means as you type in the input.
APIHooksComponent (RenderProps, Form, Field) + HooksComponent (RenderProps, Form, Field)
Package sizeSmall
react-hook-form@6.0.0
8.9KB
Medium
formik@2.1.4
15KB
Large
redux-form@8.3.6
26.4KB
ValidationBuilt-in, Yup, Joi, Superstruct and build your own.Build yourself or YupBuild your yourself or Plugins
Learning curveLowMediumMedium
StatusMedium Community and growingLarge Community: Well established form lib in the communityLarge Community: Well established form lib in the community

Can it work with Controlled components?

Short answer: Yes

react-hook-form is not recommending you to build controlled forms, however you can still achieve that easily.

The trick is to use the watch API to monitor each input's change and assign it to the value prop.

Alternatively, you can use our wrapper component Controller which registers components for you.

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField } from "@material-ui/core";

function App() {
  const { control, handleSubmit } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        as={TextField}
        name="firstName"
        control={control}
        defaultValue=""
      />
      
      <input type="submit" />
    </form>
  );
}
import React, { useEffect } from "react";
import { useForm } from "react-hook-form";

function App() {
  const { register, watch, setValue, handleSubmit } = useForm({
    defaultValues: {
      firstName: "",
      lastName: ""
    }
  });
  const { firstName, lastName } = watch();

  useEffect(() => {
    register({ name: "firstName" });
    register({ name: "lastName" });
  }, [register]);

  const handleChange = (name, e) => {
    e.persist();
    setValue(name, e.target.value);
  };

  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        onChange={handleChange.bind(null, "firstName")}
        value={firstName}
      />

      <input onChange={handleChange.bind(null, "lastName")} value={lastName} />
      <input type="submit" />
    </form>
  );
}

Testing React Hook Form

  • Why is testing not working with React Native (react-native-testing-library)?

    React Hook Form doesn't register inputs during server side render, which means testing in react native could result in the window object being undefined. A quick fix would be to stub the window object to enable the registration process.

  • Why am I getting an act warning?

    All validation methods in React Hook Form will be treated as async functions, so it's important to wrap async around your act.

  • Why doesn't input change fire events?

    React Hook Form uses input events for input changes. If you're using react-testing-library, you can easily switch to fireEvent.input. Here is a testing example at codesandbox.

    If you're using enzyme, you'll need to manually set the value of your input's DOM node, then dispatch an input event.

    const element = wrapper.find("select[data-testid='a']");
    element.getDOMNode().value = "foo";
    element.getDOMNode().dispatchEvent(new Event("input"));

watch vs getValues vs state

  • watch: subscribe to either all inputs or the specified inputs changes via event listener and re-render based on which fields that are subscribed. Check out this codesandbox for actual behaviour.

  • getValues: get values that are stored inside the custom hook as reference, fast and cheap. This method doesn’t trigger re-render.

  • local state: React local state represent more than just input’s state and also decide what to render. This will trigger on each input’s change.


Why is default value not changing correctly with ternary operator?

React Hook Form doesn't control your entire form and inputs, which is the reason why React wouldn't recognize the actual input that has been exchanged or swapped. As a solution, you can resolve this problem by giving a unique key prop to your input. You can also read more about the key props from this article written by Kent C. Dodds.

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register } = useForm();

  return (
    <div>
      {watchChecked ? (
        <input ref={register} name="input3" type="text" key="key1" defaultValue="1" />
      ) : (
        <input ref={register} name="input4" type="text" key="key2" defaultValue="2" />
      )}
    </div>
  );
}

Controller not working with shouldFocusError?

After a validation error, React Hook Form will automatically focus the invalids elements that have a proper ref, like the native inputs (eg: <input />) or some 3rd party Components that correctly export a ref (eg: from MUI <TextField inputRef={register({required: 'Field Required'})} />)

However, for some 3rd party controlled Components (like <Autocomplete> from MUI or <XX> from AntD) it's very difficult to predict its ref because the formats vary. In this case, React Hook Form will properly detect the validation error but will not be able to automatically focus that kind of Component.

As a workaround, after the validation error, you can manually focus the 3rd party controlled Component (if you can get the actual internal input ref), for example:

import React, { useEffect, useRef } from "react"
import { useForm } from "react-hook-form"

export default function App() {
  const inputRef = useRef();
  const { control, handleSubmit, errors } = useForm({});

  useEffect(() => {
    if (errors.test) {
      inputRef.current.focus();
    }
  });

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <Controller as={<ExternalInput ref={inputRef} />} name="test" control={control} rules={{ required: true }} />
      <button>Submit</button>
    </form>
  );
}

If you find difficult to make the autofocus with external controlled component work correctly, it is possible to disable the "autofocus on error" feature. It is possible that this behavior will bring a better user experience in some cases. useForm({shouldFocusError: false});


How to work with modal or tab forms?

It's important to understand React Hook Form embraces native form behavior by storing input state inside each input (except customregister at useEffect). One of the common misconceptions is that when working with modal or tab forms, by mounting and unmounting form/inputs that inputs state will remain. That is incorrect. Instead, the correct solution would be to build a new form for your form inside each modal or tab and capture your submission data in local or global state and then do something with the combined data.

We Need Your Support

If you find React Hook Form to be useful in your React project, please star to support the repo and contributors ❤

Edit