Improve verification code accessibility (#618)
This commit is contained in:
parent
e82fa93546
commit
7e7f2d8db4
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user