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>
);
};
When using the key prop in React, it's important to place it before the spread operator.
The key prop helps React identify and manage elements in a list more efficiently, especially when the list changes (like adding, removing, or reordering items).
If you place the key after the spread operator, the value of key may get overridden by the properties in the object you're spreading. This can cause unexpected behavior, as React might not assign the key correctly
Incorrect
<Input
className="mb-[20px]"
label="Last Name"
errorMessage={fields.lastName.errors?.at(0)}
{...getInputProps(fields.lastName, { type: "text" })}
/>
Correct
<Input
className="mb-[20px]"
label="Last Name"
errorMessage={fields.lastName.errors?.at(0)}
{...getInputProps(fields.lastName, { type: "text" })}
key={fields.lastName.key}
/>
Reference:https://github.com/vercel/next.js/issues/55642#issuecomment-1728746491