The component uses react-hook-form for a two-step form (email then password). After submitting the email address in the first step, the email value appears to be reset to undefined. This prevents the submission of the final form since the email is no longer available.
export default function App() {
const [inProgress, setInProgress] = useState(false);
const handleSubmit = (email: string, password: string) => {
console.log("SimplifiedSignInForTesting submitted:", { email, password });
setInProgress(true);
setTimeout(() => {
setInProgress(false);
}, 1500);
};
return <SignIn submit={handleSubmit} inProgress={inProgress} />;
}
interface SignInProps {
submit: (email: string, password: string) => void;
inProgress: boolean;
}
export const SignIn = ({ submit, inProgress }: SignInProps) => {
const [isEmailSubmitted, setIsEmailSubmitted] = useState(false);
const schema = z.object({
email: z.string(),
password: z.string(),
});
type SignInFormData = z.infer<typeof schema>;
const {
register,
handleSubmit,
setFocus,
watch,
formState: { errors, isSubmitting },
} = useForm<SignInFormData>({
resolver: zodResolver(schema),
shouldUnregister: false,
defaultValues: {
email: "",
password: "",
},
});
const onSubmitInternal = useCallback(
async (data: SignInFormData) => {
const { email, password } = data;
console.log(email, password);
if (!isEmailSubmitted) {
setIsEmailSubmitted(true);
setTimeout(() => setFocus("password"), 0);
return;
}
submit(email, password);
},
[isEmailSubmitted, setIsEmailSubmitted, submit, setFocus]
);
const isLoading = inProgress || isSubmitting;
const emailErrorMessage = errors.email?.message;
const email = watch("email");
React.useEffect(() => {
console.log(email);
}, [email]);
return (
<form onSubmit={handleSubmit(onSubmitInternal)} noValidate>
<input
tabIndex={0}
autoFocus
aria-label="email"
type="email"
disabled={isLoading || isEmailSubmitted}
{...register("email")}
/>
{emailErrorMessage && <span>{emailErrorMessage}</span>}
<input
aria-label="password"
type="password"
autoComplete="current-password"
style={{ display: isEmailSubmitted ? "initial" : "none" }}
disabled={isLoading}
tabIndex={isEmailSubmitted ? 0 : -1}
{...register("password")}
/>
<input
tabIndex={0}
type="submit"
aria-label={isEmailSubmitted ? "login" : "continue"}
/>
</form>
);
};
https://codesandbox.io/p/sandbox/affectionate-tu-6fk26l
The form submission should have both the email and password
According to handleSubmit documentation:
disabled inputs will appear as undefined values in form values. If you want to prevent users from updating an input and wish to retain the form value, you can use readOnly or disable the entire . Here is an example.
In your Form, when a user first clicks to submit the e-mail, you are disabling the field, which in turn makes the email prop undefined.
To fix this behaviour, you should remove the isEmailSubmitted
from the disabled prop, and add a new prop, readOnly with isEmailSubmitted
as value
Here you have a working example, that I forked from your codesandbox if you want to see it working