Improve verification code accessibility (#618)

This commit is contained in:
shenlan 2025-10-31 21:27:27 +08:00 committed by GitHub
parent e82fa93546
commit 7e7f2d8db4

View File

@ -11,6 +11,7 @@ import {
useMemo,
useRef,
useState,
useId,
} from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
@ -643,6 +644,7 @@ export default function RegisterContent() {
: resendCooldown > 0
? `${t.form.verificationCodeResend} (${resendCooldown}s)`
: t.form.verificationCodeResend
const verificationDescriptionId = useId()
return (
<AuthLayout
@ -679,47 +681,6 @@ export default function RegisterContent() {
disabled={isVerificationStep}
/>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-slate-600" htmlFor="verification-code-0">
{t.form.verificationCodeLabel}
</label>
<button
type="button"
onClick={handleResend}
disabled={isResending || resendCooldown > 0}
className="rounded-xl border border-slate-200 bg-white/90 px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:text-slate-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-500 disabled:cursor-not-allowed disabled:opacity-60"
>
{resendLabel}
</button>
</div>
{t.form.verificationCodeDescription ? (
<p className="text-xs text-slate-500">{t.form.verificationCodeDescription}</p>
) : null}
<div className="flex gap-2">
{codeDigits.map((digit, index) => (
<input
key={index}
id={`verification-code-${index}`}
ref={(element) => {
codeInputRefs.current[index] = element
}}
type="text"
inputMode="numeric"
autoComplete={index === 0 ? 'one-time-code' : undefined}
pattern="[0-9]*"
maxLength={1}
value={digit}
onChange={(event) => handleCodeChange(index, event.target.value)}
onKeyDown={(event) => handleCodeKeyDown(index, event)}
onPaste={(event) => handleCodePaste(index, event)}
disabled={!isVerificationStep}
className="h-12 w-12 rounded-2xl border border-slate-200 bg-white/90 text-center text-lg font-semibold text-slate-900 shadow-sm transition focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200 disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400"
aria-label={`${t.form.verificationCodeLabel} ${index + 1}`}
/>
))}
</div>
</div>
<div className="grid gap-5 sm:grid-cols-2">
<div className="space-y-2">
<label htmlFor="password" className="text-sm font-medium text-slate-600">
@ -752,6 +713,54 @@ export default function RegisterContent() {
/>
</div>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-slate-600" htmlFor="verification-code-0">
{t.form.verificationCodeLabel}
</label>
<button
type="button"
onClick={handleResend}
disabled={isResending || resendCooldown > 0}
className="rounded-xl border border-slate-200 bg-white/90 px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:text-slate-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-500 disabled:cursor-not-allowed disabled:opacity-60"
>
{resendLabel}
</button>
</div>
{t.form.verificationCodeDescription ? (
<p
id={verificationDescriptionId}
className="text-xs text-slate-500"
>
{t.form.verificationCodeDescription}
</p>
) : null}
<div className="flex gap-2">
{codeDigits.map((digit, index) => (
<input
key={index}
id={`verification-code-${index}`}
ref={(element) => {
codeInputRefs.current[index] = element
}}
type="text"
inputMode="numeric"
autoComplete={index === 0 ? 'one-time-code' : undefined}
pattern="[0-9]*"
maxLength={1}
value={digit}
onChange={(event) => handleCodeChange(index, event.target.value)}
onKeyDown={(event) => handleCodeKeyDown(index, event)}
onPaste={(event) => handleCodePaste(index, event)}
className="h-12 w-12 rounded-2xl border border-slate-200 bg-white/90 text-center text-lg font-semibold text-slate-900 shadow-sm transition focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200 disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400"
aria-label={`${t.form.verificationCodeLabel} ${index + 1}`}
aria-describedby={
t.form.verificationCodeDescription ? verificationDescriptionId : undefined
}
/>
))}
</div>
</div>
<label className="flex items-start gap-3 text-sm text-slate-600">
<input
type="checkbox"