DEV Community

Alex Spinov
Alex Spinov

Posted on

React Hook Form Has a Free API That Eliminates 90% of Form Boilerplate

React Hook Form is the most performant form library in React — and its API goes way deeper than useForm and register.

The Controller API: Controlled Components Made Easy

import { useForm, Controller } from "react-hook-form";
import { DatePicker } from "some-ui-lib";

function MyForm() {
  const { control, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="birthdate"
        control={control}
        rules={{ required: "Date is required" }}
        render={({ field, fieldState }) => (
          <>
            <DatePicker {...field} />
            {fieldState.error && <span>{fieldState.error.message}</span>}
          </>
        )}
      />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

The FormProvider API: Cross-Component Forms

import { useForm, FormProvider, useFormContext } from "react-hook-form";

function ParentForm() {
  const methods = useForm();
  return (
    <FormProvider {...methods}>
      <NestedInput />
      <DeepNestedSection />
    </FormProvider>
  );
}

function NestedInput() {
  const { register } = useFormContext(); // Access form from anywhere!
  return <input {...register("nested.field")} />;
}
Enter fullscreen mode Exit fullscreen mode

useFieldArray: Dynamic Form Fields

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

function DynamicForm() {
  const { control, register } = useForm({
    defaultValues: { items: [{ name: "" }] }
  });

  const { fields, append, remove, move } = useFieldArray({
    control,
    name: "items"
  });

  return (
    <form>
      {fields.map((field, index) => (
        <div key={field.id}>
          <input {...register(`items.${index}.name`)} />
          <button onClick={() => remove(index)}>Remove</button>
        </div>
      ))}
      <button onClick={() => append({ name: "" })}>Add Item</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Zod Integration: Schema-First Validation

import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const schema = z.object({
  email: z.string().email("Invalid email"),
  password: z.string().min(8, "Min 8 characters"),
  confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
  message: "Passwords don    match",
  path: ["confirmPassword"]
});

const { register, handleSubmit, formState: { errors } } = useForm({
  resolver: zodResolver(schema)
});
Enter fullscreen mode Exit fullscreen mode

useWatch: Performant Field Subscriptions

import { useWatch } from "react-hook-form";

function PricePreview({ control }) {
  const price = useWatch({ control, name: "price", defaultValue: 0 });
  const quantity = useWatch({ control, name: "quantity", defaultValue: 1 });
  return <p>Total: ${price * quantity}</p>; // Only re-renders when price/quantity change
}
Enter fullscreen mode Exit fullscreen mode

Why It Beats Formik

Feature React Hook Form Formik
Re-renders Minimal (uncontrolled) Every keystroke
Bundle size 8.6KB 44KB
TypeScript First-class Bolt-on
Performance O(1) O(n) fields

Building data-driven forms? My Apify scraping tools can feed structured data directly into your React forms.

Need a custom data solution? Email spinov001@gmail.com

Top comments (0)