I'm encountering an issue with form validation using react-hook-form and Yup where validation errors are reported even though the fields appear to be valid according to my Yup schema. The form includes nested fields under clientInformation, such as name.firstName and email. Despite entering valid data, validation errors such as "Email is required" and "First name is required" are being reported.
Here's a simplified version of my form component and Yup validation schema:
Form component:
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import validationSchema from "@/app/lib/validationSchema.js";
import { useEffect } from "react";
import { initialState } from "@/app/lib/initialState";
export default function ClientInformation() {
const {
register,
handleSubmit,
watch,
control,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
defaultValues: initialState,
});
const allFormValues = watch();
const onSubmit = (data) => {
console.log(data);
};
useEffect(() => {
console.log("Current Form Values:", allFormValues);
console.log("Current Form Errors:", errors);
}, [allFormValues, errors]);
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="space-y-2 divide-y divide-gray-900/10"
>
<div className="grid grid-cols-1 gap-x-2 gap-y-8 pt-2 md:grid-cols-3">
<div className="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2">
<div className="px-8 py-2 sm:p-8">
<div className="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-3">
<div className="sm:col-span-3">
<label
htmlFor="first-name"
className="block text-sm font-medium leading-6 text-gray-900"
>
First name
</label>
<div className="mt-2">
<input
type="text"
name="clientInformation.name.firstName"
id="first-name"
{...register("clientInformation.name.firstName")}
autoComplete="given-name"
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
{errors.clientInformation?.name?.firstName && (
<p className="mt-2 text-sm text-red-600">
{errors.clientInformation.name.firstName.message}
</p>
)}
</div>
</div>
<div className="sm:col-span-4">
<label
htmlFor="email"
className="block text-sm font-medium leading-6 text-gray-900"
>
Email address
</label>
<div className="mt-2">
<input
id="email"
name="clientInformation.email"
type="email"
{...register("clientInformation.email")}
autoComplete="email"
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
{errors.clientInformation?.email && (
<p className="mt-2 text-sm text-red-600">
{errors.clientInformation.email.message}
</p>
)}
</div>
</div>
</div>
</div>
</div>
</div>
<div className="flex justify-end p-6">
<button
type="submit"
className="inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Submit
</button>
</div>
</form>
);
}
);
}
Validation Schema (validationSchema.js):
import * as Yup from "yup";
const validationSchema = Yup.object().shape({
"clientInformation.name.firstName": Yup.string()
.trim()
.min(2, "First name must be at least 2 characters")
.max(30, "First name must be less than 50 characters")
.required("First name is required"),
"clientInformation.email": Yup.string()
.email("Invalid email")
.required("Email is required"),
});
Console Log Output (Errors):
{
clientInformation: {
email: { message: "Email is required", type: "optionality", ref: "undefined" },
name: {
firstName: { message: "First name is required", type: "optionality", ref: "undefined" }
}
}
}
Console Log Output (Current Values):
clientInformation: {
email: "[email protected]",
name: { firstName: 'gggg' },
// Other fields...
}
Despite the fields being populated correctly (email and firstName), I'm still receiving validation errors indicating these fields are required.
Any help would be appreciated. I've been caught out with NextJS a few times over serverless issues which are hard to figure out so I wouldn't put it past that.
Ensured field names in the form match those in the Yup schema. Verified the initialState structure matches the schema. Checked for typos in field names and schema paths.
The way you were using for creating the fields in ValidateSchema
was wrong due to which it was not able to understand what to validate.
Change the validation schema to this:
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.trim()
.min(2, "First name must be at least 2 characters")
.max(30, "First name must be less than 50 characters")
.required("First name is required"),
email: Yup.string()
.email("Invalid email")
.required("Email is required"),
});
According to this schema, change id/name of input fields too in this way:
<input
type="text"
name="firstName"
id="firstName"
...
/>
<input
type="text"
name="email"
id="email"
...
/>