React Login Form Validation
Build a login form with validation using React Hook Form and Zod.
Live preview
Code walkthrough
React Hook Form keeps form state out of React's render cycle, so even large forms stay fast. Pairing it with Zod gives you a single schema that drives both runtime validation and TypeScript types. Use View full code above for the whole component.
1. One schema, two jobs
The Zod schema validates at runtime and generates the form's TypeScript type via
z.infer, so the rules and the types can never disagree.
const schema = z.object({
email: z.string().email("Enter a valid email"),
password: z.string().min(8, "At least 8 characters"),
});
type FormValues = z.infer<typeof schema>;2. Wiring the form
useForm with zodResolver(schema) connects Zod to React Hook Form. We pull out
register (to bind inputs), handleSubmit (validates before calling us), and
formState (errors + submitting flag).
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormValues>({ resolver: zodResolver(schema) });3. Registering inputs and showing errors
{...register("email")} wires an input to the form with no useState. When validation
fails, the matching errors.* entry holds the message — render it with role="alert"
so screen readers announce it.
<input id="email" type="email" {...register("email")} />
{errors.email && <p role="alert">{errors.email.message}</p>}noValidate on the <form> turns off the browser's native bubbles so Zod is the
single source of truth for validation messages.
4. Submitting
handleSubmit(onSubmit) only calls onSubmit once the data is valid, and
isSubmitting lets you disable the button while the request is in flight.
async function onSubmit(values: FormValues) {
await fetch("/api/login", { method: "POST", body: JSON.stringify(values) });
}Related examples
Login Form UI
A clean, accessible login form component for React with email, password, and social sign-in.
View exampleForm Validation — Simple Input Validation
Validate a sign-in form by hand with useState — inline errors, validate-on-blur, and a submit guard. No libraries.
View exampleForm Validation — using Formik
Validate a sign-in form with Formik and Yup — declarative fields, a validation schema, and built-in touched/error state.
View example