I am encountering an issue where React complains about a key prop being spread into a JSX element, even though I’m not explicitly passing it as part of my props.
Here’s the relevant code snippet:
<Input
className="mb-[20px]"
label="First Name"
errorMessage={fields.firstName.errors?.at(0)}
{...getInputProps(fields.firstName, { type: "text" })}
/>
The error message:
A props object containing a "key" prop is being spread into JSX:
let props = {key: someKey, className: ..., label: ..., errorMessage: ..., required: ..., id: ..., name: ..., form: ..., type: ..., minLength: ...};
<Input {...props} />
React keys must be passed directly to JSX without using spread:
let props = {className: ..., label: ..., errorMessage: ..., required: ..., id: ..., name: ..., form: ..., type: ..., minLength: ...};
<Input key={someKey} {...props} />
Conform documentation: https://conform.guide/api/react/getInputProps
Here is the full form:
"use client";
import { useActionState } from "react";
import { getFormProps, getInputProps, useForm } from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { signUpWithDetails } from "@/features/authentication/actions";
import { SignUpSchema } from "@/features/authentication/schemas/sign-up";
import { Input } from "@/common/components/Form/Input/Input";
import { Button } from "@/common/components/Form/Button/Button";
import { DatePicker } from "@/common/components/Form/DatePicker/DatePicker";
interface DetailsFormProps {
email: string;
}
export const DetailsForm = ({ email }: DetailsFormProps) => {
const [lastResult, action, pending] = useActionState(
signUpWithDetails,
undefined,
);
const [form, fields] = useForm({
lastResult,
constraint: getZodConstraint(SignUpSchema),
onValidate({ formData }) {
return parseWithZod(formData, { schema: SignUpSchema });
},
shouldValidate: "onSubmit",
shouldRevalidate: "onInput",
});
return (
<form className="w-full" action={action} {...getFormProps(form)}>
<input type="hidden" name="email" value={email} />
<Input
className="mb-[20px]"
label="First Name"
errorMessage={fields.firstName.errors?.at(0)}
{...getInputProps(fields.firstName, { type: "text" })}
/>
<Input
className="mb-[20px]"
label="Last Name"
errorMessage={fields.lastName.errors?.at(0)}
{...getInputProps(fields.lastName, { type: "text" })}
/>
<DatePicker
className="mb-[20px]"
label="Date of Birth"
max={new Date().toJSON().slice(0, 10)}
errorMessage={fields.dateOfBirth?.errors?.at(0)}
{...getInputProps(fields.dateOfBirth, { type: "date" })}
/>
<Input
className="mb-10"
label="Password"
errorMessage={fields.password.errors?.at(0)}
{...getInputProps(fields.password, { type: "password" })}
/>
<Button
className="w-full mb-6"
label="Continue"
variant="primary"
type="submit"
isLoading={pending}
/>
</form>
);
};