I am using React Hook Form to handle form validation in my React project. While everything works fine when using plain elements, I encounter issues when I try to wrap the inputs in a custom component. Specifically, validations such as minLength and maxLength are not being triggered properly. It is always countering the required validation.
Here’s an example of my setup: Parent Component (Parent.jsx):
import { useForm } from "react-hook-form";
import Input from "./Components/Input.jsx";
import Button from "./Components/Button.jsx";
export default function Parent() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const login = (data) => {
console.log("Form Data:", data);
};
return (
<div className="App">
<div className="container">
<form onSubmit={handleSubmit(login)}>
<Input
type="text"
name="username"
{...register("username", {
required: {
value: true,
message: "Username is required",
},
minLength: {
value: 5,
message: "Too Few Characters",
},
maxLength: {
value: 15,
message: "username length should not exceed 15",
},
})}
/>
{errors.username && <p className="red">{errors.username.message}</p>}
<Input
type="password"
name="password"
{...register("password", {
required: {
value: true,
message: "password is required",
},
minLength: {
value: 6,
message: "Password length should be greater than 6",
},
maxLength: {
value: 15,
message: "Password length should not exceed 15",
},
})}
/>
{errors.password && <p className="error-red">{errors.password.message}</p>}
<Button type="submit" />
</form>
</div>
</div>
);
}
custom Input Component (Input.jsx):
import { forwardRef } from "react";
const Input = forwardRef(function Input(
{ type = "text", name = "", ...props },
ref
) {
return (
<>
<input
placeholder=" "
className="txt-input"
type={type}
ref={ref}
{...props}
/>
{name && (
<label className="label-placeholder">
{name.charAt(0).toUpperCase() + name.slice(1)}
</label>
)}
</>
);
});
export default Input;
The Input
component should pass/forward all field props to the underlying input
element, e.g. the missing name
prop so react-hook-form
can validate the field data correctly.
And for accessibility, you may also want to connect the rendered label
to the input
since it's not wrapping it so when it's clicked/interacted with the input is focused.
Example:
const Input = forwardRef(function Input(
{ name = "", type = "text", ...props },
ref
) {
return (
<>
<input
ref={ref}
className="txt-input"
id={name} // <-- for accessibility with label
name={name} // <-- for field validation
placeholder=" "
type={type}
{...props}
/>
{name && (
<label
className="label-placeholder"
htmlFor={name} // <-- for accessibility with input
>
{name.charAt(0).toUpperCase() + name.slice(1)}
</label>
)}
</>
);
});