Focus the email field after clearing it via "andere E-Mail-Adresse"

FormField is now forwardRef so the email input can be targeted
imperatively — clicking the button clears the field (previous commit)
and now also focuses it, so the shopper can start typing immediately
instead of having to click in first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-24 18:04:56 +00:00
parent 9f92f7324a
commit a3fb864f7d
+17 -8
View File
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { forwardRef, useEffect, useRef, useState } from "react";
import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/navigation";
@@ -69,17 +69,20 @@ function validateVatIdFormat(value: string): string {
return isValidVatId(normalizeVatId(value)) ? "" : "Ungültiges USt-IdNr.-Format (z. B. DE123456789).";
}
function FormField({
label,
wrapperClassName = "flex-1 min-w-0",
error,
...props
}: { label: string; wrapperClassName?: string; error?: string } & React.InputHTMLAttributes<HTMLInputElement>) {
// forwardRef so callers can imperatively .focus() a specific field (see
// the "Andere E-Mail-Adresse verwenden" handler below) — plain props
// couldn't do that, and every other FormField usage is unaffected since
// ref is optional.
const FormField = forwardRef<
HTMLInputElement,
{ label: string; wrapperClassName?: string; error?: string } & React.InputHTMLAttributes<HTMLInputElement>
>(function FormField({ label, wrapperClassName = "flex-1 min-w-0", error, ...props }, ref) {
return (
<label className={`flex flex-col gap-2 items-start ${wrapperClassName}`}>
<span className="text-label text-text-muted">{label}</span>
<input
{...props}
ref={ref}
aria-invalid={error ? true : undefined}
className={`w-full border rounded-sm px-4 py-3 text-body-sm text-text-primary outline-none focus:border-brand transition-colors ${
error ? "border-red-600" : "border-border"
@@ -88,7 +91,7 @@ function FormField({
{error && <span className="text-label text-red-600">{error}</span>}
</label>
);
}
});
export function CheckoutContent({
shippingMethods,
@@ -150,6 +153,10 @@ export function CheckoutContent({
// down the page without ever blurring the email field first (e.g.
// browser autofill).
const loginGateRef = useRef<HTMLDivElement>(null);
// Focused after "Andere E-Mail-Adresse verwenden" clears the field below
// — the shopper explicitly asked to type a different one, so the cursor
// should already be waiting there instead of making them click in.
const emailInputRef = useRef<HTMLInputElement>(null);
const [loginPassword, setLoginPassword] = useState("");
const [loginError, setLoginError] = useState<string | null>(null);
const [loggingIn, setLoggingIn] = useState(false);
@@ -753,6 +760,7 @@ export function CheckoutContent({
actual rendered width in the 2-col row above (each half of
a gap-4 flex row), instead of stretching full-width. */}
<FormField
ref={emailInputRef}
label="E-Mail-Adresse"
name="email"
type="email"
@@ -812,6 +820,7 @@ export function CheckoutContent({
setEmail("");
setLoginPassword("");
setFieldError("email", "");
emailInputRef.current?.focus();
}}
className="text-label text-text-muted underline hover:text-text-primary transition-colors"
>