feat(a11y): landmark regions, skip link, dialog labels, icon button labels

C-3: nav/main landmark roles in ClientLayout (nav + main areas)
C-4: Skip-to-main-content link in ClientLayout (visually hidden, focusable)
H-2: aria-labelledby on LeaveRoomPrompt and RoomTopicViewer dialogs
C-1: aria-label on ~15 icon-only buttons (back, menu, close, folder, account)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lotus Bot
2026-05-20 21:44:41 -04:00
parent ee7eabd2c4
commit 4490993fe7
17 changed files with 42 additions and 20 deletions
@@ -56,7 +56,7 @@ export function LeaveRoomPrompt({ roomId, onDone, onCancel }: LeaveRoomPromptPro
escapeDeactivates: stopPropagation,
}}
>
<Dialog variant="Surface">
<Dialog variant="Surface" aria-labelledby="leave-room-dialog-title">
<Header
style={{
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
@@ -66,7 +66,7 @@ export function LeaveRoomPrompt({ roomId, onDone, onCancel }: LeaveRoomPromptPro
size="500"
>
<Box grow="Yes">
<Text size="H4">Leave Room</Text>
<Text 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} />
@@ -17,12 +17,13 @@ export const RoomTopicViewer = as<
size="300"
flexHeight
className={classNames(css.ModalFlex, className)}
aria-labelledby="room-topic-title"
{...props}
ref={ref}
>
<Header className={css.ModalHeader} variant="Surface" size="500">
<Box grow="Yes">
<Text size="H4" truncate>
<Text size="H4" truncate id="room-topic-title">
{name}
</Text>
</Box>
+24 -4
View File
@@ -7,9 +7,29 @@ type ClientLayoutProps = {
};
export function ClientLayout({ nav, children }: ClientLayoutProps) {
return (
<Box grow="Yes">
<Box shrink="No">{nav}</Box>
<Box grow="Yes">{children}</Box>
</Box>
<>
<a
href="#main-content"
style={{
position: 'absolute',
top: '-40px',
left: 0,
padding: '8px 16px',
background: '#000',
color: '#fff',
zIndex: 9999,
borderRadius: '0 0 4px 0',
transition: 'top 0.1s',
}}
onFocus={(e) => { (e.currentTarget as HTMLElement).style.top = '0'; }}
onBlur={(e) => { (e.currentTarget as HTMLElement).style.top = '-40px'; }}
>
Skip to main content
</a>
<Box grow="Yes">
<Box shrink="No" as="nav" aria-label="Room navigation">{nav}</Box>
<Box grow="Yes" as="main" id="main-content">{children}</Box>
</Box>
</>
);
}
+1
View File
@@ -69,6 +69,7 @@ function ClientRootOptions({ mx }: { mx?: MatrixClient }) {
variant="Background"
fill="None"
onClick={handleToggle}
aria-label="Account options"
>
<Icon size="200" src={Icons.VerticalDots} />
<PopOut
+1 -1
View File
@@ -107,7 +107,7 @@ function DirectHeader() {
</Text>
</Box>
<Box>
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu}>
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu} aria-label="Direct messages options">
<Icon src={Icons.VerticalDots} size="200" />
</IconButton>
</Box>
+1 -1
View File
@@ -44,7 +44,7 @@ export function DirectCreate() {
<Box grow="Yes" alignItems="Center" gap="200">
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -96,7 +96,7 @@ export function AddServer() {
<Box grow="Yes">
<Text size="H4">Add Server</Text>
</Box>
<IconButton size="300" onClick={() => setDialog(false)} radii="300">
<IconButton size="300" onClick={() => setDialog(false)} radii="300" aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+1 -1
View File
@@ -33,7 +33,7 @@ export function FeaturedRooms() {
<Box shrink="No">
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -499,7 +499,7 @@ export function PublicRooms() {
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -25,7 +25,7 @@ export function HomeCreateRoom() {
<Box grow="Yes" alignItems="Center" gap="200">
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -121,7 +121,7 @@ function HomeHeader() {
</Text>
</Box>
<Box>
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu}>
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu} aria-label="Home options">
<Icon src={Icons.VerticalDots} size="200" />
</IconButton>
</Box>
+1 -1
View File
@@ -19,7 +19,7 @@ export function HomeSearch() {
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -753,7 +753,7 @@ export function Invites() {
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -642,7 +642,7 @@ export function Notifications() {
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -522,7 +522,7 @@ function OpenedSpaceFolder({ folder, onClose, children }: OpenedSpaceFolderProps
>
<SidebarFolderDropTarget ref={aboveTargetRef} position="Top" />
<SidebarAvatar size="300">
<IconButton data-id={folder.id} size="300" variant="Background" onClick={onClose}>
<IconButton data-id={folder.id} size="300" variant="Background" onClick={onClose} aria-label="Close folder">
<Icon size="400" src={Icons.ChevronTop} filled />
</IconButton>
</SidebarAvatar>
+1 -1
View File
@@ -34,7 +34,7 @@ export function SpaceSearch() {
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
+1 -1
View File
@@ -273,7 +273,7 @@ function SpaceHeader() {
{joinRules?.join_rule !== JoinRule.Public && <Icon src={Icons.Lock} size="50" />}
</Box>
<Box shrink="No">
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu}>
<IconButton aria-pressed={!!menuAnchor} variant="Background" onClick={handleOpenMenu} aria-label="Space options">
<Icon src={Icons.VerticalDots} size="200" />
</IconButton>
</Box>