From 996e815d578f0140f7eea6fab0e619aa344a105c Mon Sep 17 00:00:00 2001 From: jackiettran <41605212+jackiettran@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:43:08 -0500 Subject: [PATCH] if authmodal is up, cursor is already in it --- frontend/src/components/AuthModal.tsx | 53 ++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/AuthModal.tsx b/frontend/src/components/AuthModal.tsx index b590311..2585ad5 100644 --- a/frontend/src/components/AuthModal.tsx +++ b/frontend/src/components/AuthModal.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef, useCallback } from "react"; import { useAuth } from "../contexts/AuthContext"; import PasswordStrengthMeter from "./PasswordStrengthMeter"; import PasswordInput from "./PasswordInput"; @@ -27,6 +27,7 @@ const AuthModal: React.FC = ({ const [showVerificationModal, setShowVerificationModal] = useState(false); const { login, register } = useAuth(); + const modalRef = useRef(null); // Update mode when modal is opened with different initialMode useEffect(() => { @@ -35,6 +36,54 @@ const AuthModal: React.FC = ({ } }, [show, initialMode]); + // Focus trapping for accessibility + const handleKeyDown = useCallback((e: KeyboardEvent) => { + if (e.key !== "Tab" || !modalRef.current) return; + + const focusableElements = modalRef.current.querySelectorAll( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' + ); + const focusableArray = Array.from(focusableElements).filter( + (el) => !el.hasAttribute("disabled") && el.offsetParent !== null + ); + + if (focusableArray.length === 0) return; + + const firstElement = focusableArray[0]; + const lastElement = focusableArray[focusableArray.length - 1]; + + if (e.shiftKey) { + // Shift + Tab: if on first element, go to last + if (document.activeElement === firstElement) { + e.preventDefault(); + lastElement.focus(); + } + } else { + // Tab: if on last element, go to first + if (document.activeElement === lastElement) { + e.preventDefault(); + firstElement.focus(); + } + } + }, []); + + // Set up focus trap and initial focus when modal is shown + useEffect(() => { + if (show && !showForgotPassword && !showVerificationModal) { + document.addEventListener("keydown", handleKeyDown); + + // Focus the first input element when modal opens + if (modalRef.current) { + const firstInput = modalRef.current.querySelector('input'); + firstInput?.focus(); + } + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + } + }, [show, showForgotPassword, showVerificationModal, handleKeyDown]); + const resetModal = () => { setError(""); setEmail(""); @@ -119,7 +168,7 @@ const AuthModal: React.FC = ({ style={{ backgroundColor: "rgba(0,0,0,0.5)" }} >
-
+