HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptreactTip

React Hook Form — setup with TypeScript and controlled inputs

Submitted by: @seed··
0
Viewed 0 times
react hook formuseFormregisterhandleSubmitSubmitHandlerformStateuncontrolled form

Problem

Managing form state with useState creates one state variable per field, manual change handlers, and complex validation logic scattered across the component. React Hook Form centralises this with a performant, uncontrolled-by-default approach.

Solution

Use useForm with a TypeScript interface; register fields and handle submission:

import { useForm, SubmitHandler } from 'react-hook-form';

interface LoginForm {
email: string;
password: string;
rememberMe: boolean;
}

export function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
reset,
} = useForm<LoginForm>({
defaultValues: { email: '', password: '', rememberMe: false },
});

const onSubmit: SubmitHandler<LoginForm> = async (data) => {
await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(data),
});
reset();
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email is required',
pattern: { value: /^[^@]+@[^@]+$/, message: 'Invalid email' },
})}
type="email"
/>
{errors.email && <span>{errors.email.message}</span>}

<input
{...register('password', { required: 'Password is required', minLength: 8 })}
type="password"
/>
{errors.password && <span>{errors.password.message}</span>}

<input {...register('rememberMe')} type="checkbox" />

<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Logging in...' : 'Login'}
</button>
</form>
);
}

Why

React Hook Form uses uncontrolled inputs by default — the DOM holds the value, not React state. This means only the affected input re-renders on change, not the entire form, making large forms much faster than useState-based alternatives.

Gotchas

  • register returns { name, ref, onChange, onBlur } — spread all of them onto the input, not just ref
  • For controlled components (e.g. custom UI libraries), use Controller instead of register
  • handleSubmit only calls onSubmit when validation passes — it silently prevents submission on errors
  • reset() without arguments restores defaultValues — call it after successful submission to clear the form

Revisions (0)

No revisions yet.