Here is a codesandbox to see my problem replicated: https://codesandbox.io/s/inspiring-haslett-1c8sw?file=/pages/index.js
I want to ensure the confirmPassword field matches the password field, however it will always say “Passwords match”, it never changes.
I have followed the docs however I cannot seem to get the functionality im after. I have set the mode to onChange
Here is my form:
import { SubmitHandler, useForm, useFormState } from "react-hook-form";
function IndexPage() {
//Hook form
const {
register,
watch,
formState: { errors, isValid, dirtyFields }
} = useForm({
mode: "onChange",
defaultValues: {
email: "",
password: "",
confirmPassword: "",
username: "",
firstName: "",
surname: "",
isShop: false
}
});
const { password } = watch();
const [passwordFocused, setPasswordFocused] = useState(false);
const onSubmit = async (data) => {
//submit here
};
return (
<>
{/* NEW SIGNUP FORM */}
<main className="min-h-screen flex">
<div className="w-full flex flex-col py-12 md:w-1/2 flex-grow min-h-full">
<div className="mt-6 h-full w-full flex flex-col md:w-96 mx-auto">
<form
onSubmit={onSubmit}
autoComplete="off"
className="space-y-6 relative flex flex-col w-full flex-1"
>
<span className="flex-1"></span>
{/* STEP 1*/}
<div>
<div className="space-y-1">
<label
htmlFor="password"
className="block text-sm font-medium text-gray-700"
>
Password
</label>
<div className="mt-1">
<input
{...register("password", {
required: true,
minLength: 8,
maxLength: 50,
pattern: /^(?=.*[A-Za-z])(?=.*d)[A-Za-zd@$!%*#?&^_-]{8,}$/
})}
id="password"
name="password"
type="password"
autoComplete="current-password"
required
className="input w-full"
onFocus={() => {
setPasswordFocused(true);
}}
onBlur={() => {
setPasswordFocused(false);
}}
/>
<span
className={`${
passwordFocused && errors.password
? "max-h-46 opacity-100"
: "max-h-0 opacity-0"
} duration-500 ease-in-out transition-all flex flex-col overflow-hidden`}
>
<p className="text-gray-600 mt-2">
Passwords must contain:
</p>
<ul className="space-y-2">
<li
className={`mt-2 ${
password.length >= 8
? "text-green-600"
: "text-gray-600"
}`}
>
At least 8 characters
</li>
<li
className={`mt-2 ${
/[A-Z]/.test(password)
? "text-green-600"
: "text-gray-600"
}`}
>
Upper and lower case characters
</li>
<li
className={`mt-2 ${
/d/.test(password)
? "text-green-600"
: "text-gray-600"
}`}
>
At least one digit
</li>
</ul>
</span>
</div>
</div>
<div
className={`space-y-1 ${
!errors.password && dirtyFields.password
? "visible"
: "invisible"
} `}
>
<label
htmlFor="password"
className="block text-sm font-medium text-gray-700"
>
Confirm password
</label>
<div className="mt-1">
<input
{...register("confirmPassword", {
validate: (value) =>
value === password || "Passwords do not match"
})}
id="confirm-password"
name="confirm-password"
type="password"
autoComplete="confirm-password"
required
className={`input w-full`}
/>
</div>
{errors.confirmPassword
? "Passwords do not match"
: "Passwords match"}
</div>
</div>
</form>
</div>
</div>
</main>
</>
);
}
export default IndexPage;