fix(a11y): semantic headings, htmlFor/id associations, remove duplicate aria-labels
H-tag: add as=h1/h2 to dialog/UIA/auth headings (21 components) Label: add htmlFor/id to PasswordRegisterForm (5 pairs) and PasswordResetForm (3 pairs) Dupe: remove duplicate aria-label from Controls.tsx screenshare button, MembersDrawer, Members, RoomInput Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -259,7 +259,7 @@ export function DeviceVerification({ request, onExit }: DeviceVerificationProps)
|
||||
<Dialog variant="Surface">
|
||||
<Header style={DialogHeaderStyles} variant="Surface" size="500">
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Device Verification</Text>
|
||||
<Text as="h2" size="H4">Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton size="300" radii="300" onClick={handleCancel} aria-label="Cancel verification">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -299,7 +299,7 @@ export const DeviceVerificationSetup = forwardRef<HTMLDivElement, DeviceVerifica
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Setup Device Verification</Text>
|
||||
<Text as="h2" size="H4">Setup Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton size="300" radii="300" onClick={onCancel} aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
@@ -334,7 +334,7 @@ export const DeviceVerificationReset = forwardRef<HTMLDivElement, DeviceVerifica
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Reset Device Verification</Text>
|
||||
<Text as="h2" size="H4">Reset Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton size="300" radii="300" onClick={onCancel} aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -43,7 +43,7 @@ export const LogoutDialog = forwardRef<HTMLDivElement, LogoutDialogProps>(
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Logout</Text>
|
||||
<Text as="h2" size="H4">Logout</Text>
|
||||
</Box>
|
||||
</Header>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
|
||||
@@ -80,7 +80,7 @@ export function JoinAddressPrompt({ onOpen, onCancel }: JoinAddressProps) {
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Join with Address</Text>
|
||||
<Text as="h2" size="H4">Join with Address</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -66,7 +66,7 @@ export function LeaveRoomPrompt({ roomId, onDone, onCancel }: LeaveRoomPromptPro
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4" id="leave-room-dialog-title">Leave Room</Text>
|
||||
<Text as="h2" size="H4" id="leave-room-dialog-title">Leave Room</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -66,7 +66,7 @@ export function LeaveSpacePrompt({ roomId, onDone, onCancel }: LeaveSpacePromptP
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Leave Space</Text>
|
||||
<Text as="h2" size="H4">Leave Space</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -23,7 +23,7 @@ export const RoomTopicViewer = as<
|
||||
>
|
||||
<Header className={css.ModalHeader} variant="Surface" size="500">
|
||||
<Box grow="Yes">
|
||||
<Text size="H4" truncate id="room-topic-title">
|
||||
<Text as="h2" size="H4" truncate id="room-topic-title">
|
||||
{name}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
@@ -18,7 +18,7 @@ function DummyErrorDialog({
|
||||
<Dialog>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="H4">{title}</Text>
|
||||
<Text as="h2" size="H4">{title}</Text>
|
||||
<Text>{message}</Text>
|
||||
</Box>
|
||||
<Button variant="Critical" onClick={onRetry}>
|
||||
|
||||
@@ -37,7 +37,7 @@ function EmailErrorDialog({
|
||||
gap="400"
|
||||
>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="H4">{title}</Text>
|
||||
<Text as="h2" size="H4">{title}</Text>
|
||||
<Text>{message}</Text>
|
||||
<Text as="label" htmlFor="retryEmailInput" size="L400" style={{ paddingTop: config.space.S400 }}>
|
||||
Email
|
||||
@@ -141,7 +141,7 @@ export function EmailStageDialog({
|
||||
<Dialog>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="H4">Verification Request Sent</Text>
|
||||
<Text as="h2" size="H4">Verification Request Sent</Text>
|
||||
<Text>{`Please check your email "${emailTokenState.data.email}" and validate before continuing further.`}</Text>
|
||||
|
||||
{errorCode && (
|
||||
|
||||
@@ -43,7 +43,7 @@ export function PasswordStage({
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Account Password</Text>
|
||||
<Text as="h2" size="H4">Account Password</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -35,7 +35,7 @@ function RegistrationTokenErrorDialog({
|
||||
gap="400"
|
||||
>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="H4">{title}</Text>
|
||||
<Text as="h2" size="H4">{title}</Text>
|
||||
<Text>{message}</Text>
|
||||
<Text as="label" htmlFor="retryTokenInput" size="L400" style={{ paddingTop: config.space.S400 }}>
|
||||
Registration Token
|
||||
|
||||
@@ -54,7 +54,7 @@ export function SSOStage({
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">SSO Login</Text>
|
||||
<Text as="h2" size="H4">SSO Login</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -18,7 +18,7 @@ function TermsErrorDialog({
|
||||
<Dialog>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="H4">{title}</Text>
|
||||
<Text as="h2" size="H4">{title}</Text>
|
||||
<Text>{message}</Text>
|
||||
</Box>
|
||||
<Button variant="Critical" onClick={onRetry}>
|
||||
|
||||
@@ -68,7 +68,7 @@ function SelfDemoteAlert({ power, onCancel, onChange }: SelfDemoteAlertProps) {
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Self Demotion</Text>
|
||||
<Text as="h2" size="H4">Self Demotion</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
@@ -118,7 +118,7 @@ function SharedPowerAlert({ power, onCancel, onChange }: SharedPowerAlertProps)
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Shared Power</Text>
|
||||
<Text as="h2" size="H4">Shared Power</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -198,7 +198,7 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM
|
||||
}}
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Add Existing</Text>
|
||||
<Text as="h2" size="H4">Add Existing</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton size="300" radii="300" onClick={requestClose} aria-label="Close">
|
||||
|
||||
@@ -146,7 +146,6 @@ export function ScreenShareButton({ enabled, onToggle }: ScreenShareButtonProps)
|
||||
radii="400"
|
||||
size="400"
|
||||
onClick={() => onToggle()}
|
||||
aria-label={enabled ? 'Stop Video' : 'Start Video'}
|
||||
aria-label={enabled ? 'Stop Screenshare' : 'Start Screenshare'}
|
||||
outlined
|
||||
>
|
||||
|
||||
@@ -121,7 +121,7 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Enable Encryption</Text>
|
||||
<Text as="h2" size="H4">Enable Encryption</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={() => setPrompt(false)} radii="300" aria-label="Cancel">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -103,7 +103,7 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
||||
<Text as="h2" size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={requestClose} radii="300" aria-label="Close">
|
||||
<Icon src={Icons.Cross} />
|
||||
|
||||
@@ -283,7 +283,6 @@ export function Members({ requestClose }: MembersProps) {
|
||||
radii="Pill"
|
||||
outlined
|
||||
size="300"
|
||||
aria-label="Scroll to Top"
|
||||
>
|
||||
<Icon src={Icons.ChevronTop} size="300" />
|
||||
</IconButton>
|
||||
|
||||
@@ -366,7 +366,6 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
|
||||
radii="Pill"
|
||||
outlined
|
||||
size="300"
|
||||
aria-label="Scroll to Top"
|
||||
>
|
||||
<Icon src={Icons.ChevronTop} size="300" />
|
||||
</IconButton>
|
||||
|
||||
@@ -808,7 +808,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
aria-label="Share location"
|
||||
title="Share location"
|
||||
>
|
||||
{locating ? (
|
||||
|
||||
@@ -56,7 +56,7 @@ export function Login() {
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="500">
|
||||
<Text size="H2" priority="400">
|
||||
<Text as="h1" size="H2" priority="400">
|
||||
Login
|
||||
</Text>
|
||||
{parsedFlows.token && loginSearchParams.loginToken && (
|
||||
|
||||
@@ -258,12 +258,13 @@ export function PasswordRegisterForm({
|
||||
<>
|
||||
<Box as="form" onSubmit={handleSubmit} direction="Inherit" gap="400">
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="usernameInput">
|
||||
Username
|
||||
</Text>
|
||||
<Input
|
||||
variant="Background"
|
||||
defaultValue={defaultUsername}
|
||||
id="usernameInput"
|
||||
name="usernameInput"
|
||||
aria-label="Username"
|
||||
size="500"
|
||||
@@ -284,12 +285,13 @@ export function PasswordRegisterForm({
|
||||
{(match, doMatch, passRef, confPassRef) => (
|
||||
<>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="passwordInput">
|
||||
Password
|
||||
</Text>
|
||||
<PasswordInput
|
||||
ref={passRef}
|
||||
onChange={doMatch}
|
||||
id="passwordInput"
|
||||
name="passwordInput"
|
||||
aria-label="Password"
|
||||
variant="Background"
|
||||
@@ -315,12 +317,13 @@ export function PasswordRegisterForm({
|
||||
)}
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="confirmPasswordInput">
|
||||
Confirm Password
|
||||
</Text>
|
||||
<PasswordInput
|
||||
ref={confPassRef}
|
||||
onChange={doMatch}
|
||||
id="confirmPasswordInput"
|
||||
name="confirmPasswordInput"
|
||||
aria-label="Confirm password"
|
||||
variant="Background"
|
||||
@@ -335,7 +338,7 @@ export function PasswordRegisterForm({
|
||||
</ConfirmPasswordMatch>
|
||||
{hasStageInFlows(uiaFlows, AuthType.RegistrationToken) && (
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="tokenInput">
|
||||
{requiredStageInFlows(uiaFlows, AuthType.RegistrationToken)
|
||||
? 'Registration Token'
|
||||
: 'Registration Token (Optional)'}
|
||||
@@ -343,6 +346,7 @@ export function PasswordRegisterForm({
|
||||
<Input
|
||||
variant="Background"
|
||||
defaultValue={defaultRegisterToken}
|
||||
id="tokenInput"
|
||||
name="tokenInput"
|
||||
aria-label="Registration token"
|
||||
size="500"
|
||||
@@ -353,12 +357,13 @@ export function PasswordRegisterForm({
|
||||
)}
|
||||
{hasStageInFlows(uiaFlows, AuthType.Email) && (
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="emailInput">
|
||||
{requiredStageInFlows(uiaFlows, AuthType.Email) ? 'Email' : 'Email (Optional)'}
|
||||
</Text>
|
||||
<Input
|
||||
variant="Background"
|
||||
defaultValue={defaultEmail}
|
||||
id="emailInput"
|
||||
name="emailInput"
|
||||
aria-label="Email address"
|
||||
type="email"
|
||||
|
||||
@@ -170,12 +170,13 @@ export function PasswordResetForm({ defaultEmail }: PasswordResetFormProps) {
|
||||
Homeserver <strong>{server}</strong> will send you an email to let you reset your password.
|
||||
</Text>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="emailInput">
|
||||
Email
|
||||
</Text>
|
||||
<Input
|
||||
defaultValue={defaultEmail}
|
||||
type="email"
|
||||
id="emailInput"
|
||||
name="emailInput"
|
||||
aria-label="Email address"
|
||||
variant="Background"
|
||||
@@ -193,12 +194,13 @@ export function PasswordResetForm({ defaultEmail }: PasswordResetFormProps) {
|
||||
{(match, doMatch, passRef, confPassRef) => (
|
||||
<>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="passwordInput">
|
||||
New Password
|
||||
</Text>
|
||||
<PasswordInput
|
||||
ref={passRef}
|
||||
onChange={doMatch}
|
||||
id="passwordInput"
|
||||
name="passwordInput"
|
||||
aria-label="New password"
|
||||
variant="Background"
|
||||
@@ -208,12 +210,13 @@ export function PasswordResetForm({ defaultEmail }: PasswordResetFormProps) {
|
||||
/>
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text as="label" size="L400" priority="300">
|
||||
<Text as="label" size="L400" priority="300" htmlFor="confirmPasswordInput">
|
||||
Confirm Password
|
||||
</Text>
|
||||
<PasswordInput
|
||||
ref={confPassRef}
|
||||
onChange={doMatch}
|
||||
id="confirmPasswordInput"
|
||||
name="confirmPasswordInput"
|
||||
aria-label="Confirm new password"
|
||||
variant="Background"
|
||||
|
||||
Reference in New Issue
Block a user