From 4af7900daee328d7db54a1409930724f65498a73 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Sat, 20 Dec 2025 22:06:53 -0500 Subject: [PATCH] auto focus 2fa --- src/components/LoginForm.tsx | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx index 0bfdc90d..ea6ce2ee 100644 --- a/src/components/LoginForm.tsx +++ b/src/components/LoginForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useRef } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; @@ -84,6 +84,7 @@ export default function LoginForm({ const [mfaRequested, setMfaRequested] = useState(false); const [showSecurityKeyPrompt, setShowSecurityKeyPrompt] = useState(false); + const otpContainerRef = useRef(null); const t = useTranslations(); const currentHost = @@ -112,6 +113,45 @@ export default function LoginForm({ } }, []); + // Auto-focus MFA input when MFA is requested + useEffect(() => { + if (!mfaRequested) return; + + const focusInput = () => { + // Try using the ref first + if (otpContainerRef.current) { + const hiddenInput = otpContainerRef.current.querySelector('input') as HTMLInputElement; + if (hiddenInput) { + hiddenInput.focus(); + return; + } + } + + // Fallback: query the DOM + const otpContainer = document.querySelector('[data-slot="input-otp"]'); + if (!otpContainer) return; + + const hiddenInput = otpContainer.querySelector('input') as HTMLInputElement; + if (hiddenInput) { + hiddenInput.focus(); + return; + } + + // Last resort: click the first slot + const firstSlot = otpContainer.querySelector('[data-slot="input-otp-slot"]') as HTMLElement; + if (firstSlot) { + firstSlot.click(); + } + }; + + // Use requestAnimationFrame to wait for the next paint + requestAnimationFrame(() => { + requestAnimationFrame(() => { + focusInput(); + }); + }); + }, [mfaRequested]); + const formSchema = z.object({ email: z.string().email({ message: t("emailInvalid") }), password: z.string().min(8, { message: t("passwordRequirementsChars") }) @@ -468,10 +508,11 @@ export default function LoginForm({ render={({ field }) => ( -
+