Files
coder/site/index.html
T
Jaayden Halko 4e2640e506 fix(site): WCAG 2.1 AA remediation — landmarks, semantics, and a11y tooling (#22746)
## Summary

Targeted WCAG 2.1 AA accessibility remediation — continuation of #22673
— addressing remaining semantic, landmark, and tooling gaps identified
in the frontend accessibility review.

### Changes

#### Document semantics (WCAG 3.1.1)
- **`site/index.html`**: Added `<html lang="en">` root wrapper so screen
readers and browser features correctly identify the document language.

#### Landmark & bypass (WCAG 1.3.1, 2.4.1)
- **`DashboardLayout.tsx`**: Replaced `<div id="main-content">` with
`<main id="main-content">` so assistive technology exposes a proper main
landmark and the skip link targets a semantic region.

#### Table header relationships (WCAG 1.3.1)
- **`Table.tsx`**: `TableHead` now renders `scope="col"` by default
(overridable via prop), giving data cells an explicit header
relationship.

#### Semantic interactive controls (WCAG 2.1.1, 4.1.2)
- **`AuditLogRow.tsx`**: Replaced `<div role="button" tabIndex={0}>`
with native `<button type="button">`, removing the manual keyboard
handler (native button provides Enter/Space for free).
- **`Autocomplete.tsx`**: Replaced clear `<span role="button"
tabIndex={0}>` with native `<button type="button" aria-label="Clear
selection">`.

#### Reduced motion (WCAG 2.3.3 best practice)
- **`index.css`**: Added global `@media (prefers-reduced-motion:
reduce)` block that suppresses non-essential animations and transitions.

#### Accessibility regression tooling
- **Storybook**: Added `@storybook/addon-a11y` (version-matched to
existing Storybook 10.x).
- **vitest-axe**: Added `vitest-axe` with setup wiring and an exemplar
`Table.axe.test.tsx` that runs axe-core assertions in vitest.

### Test plan

- 12 new/updated tests pass across 5 test files:
  - `DashboardLayout.test.tsx` — main landmark + skip link behavior
  - `Table.test.tsx` — scope default + override
  - `Table.axe.test.tsx` — axe-core violation scan
  - `AuditPage.test.tsx` — keyboard toggle with native button
  - `Autocomplete.test.tsx` — clear control semantics
- `pnpm lint` clean (biome, TypeScript, circular deps)
- Manual keyboard traversal: skip link → main content, audit row toggle,
autocomplete clear
2026-03-13 10:47:53 +00:00

66 lines
2.4 KiB
HTML

<!doctype html>
<!--
-####### +######- ########+ ########## ########+. ###########
+#####--###### +#####--#####+ ############ ########## ####+++#####- ###########
####- -#### ####- ##### #### ####+ #### #### .#### ###########
.#### #### #### #### #### ######### ####...+##+ ###########
####. .#### #### +#### #### +#### #### ####+####### ###########
#####- -##### ######..###### ############- ########## #### ##### ###########
.########+ -########. #########+ ########## #### .#### ###########
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Coder</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#17172E" />
<meta name="application-name" content="{{ .ApplicationName }}" />
<meta property="og:type" content="website" />
<meta property="csrf-token" content="{{ .CSRF.Token }}" />
<meta property="build-info" content="{{ .BuildInfo }}" />
<meta property="user" content="{{ .User }}" />
<meta property="entitlements" content="{{ .Entitlements }}" />
<meta property="appearance" content="{{ .Appearance }}" />
<meta property="userAppearance" content="{{ .UserAppearance }}" />
<meta property="experiments" content="{{ .Experiments }}" />
<meta property="regions" content="{{ .Regions }}" />
<meta property="docs-url" content="{{ .DocsURL }}" />
<meta property="logo-url" content="{{ .LogoURL }}" />
<meta property="tasks-tab-visible" content="{{ .TasksTabVisible }}" />
<meta property="agents-tab-visible" content="{{ .AgentsTabVisible }}" />
<meta property="permissions" content="{{ .Permissions }}" />
<meta property="organizations" content="{{ .Organizations }}" />
<link
rel="alternate icon"
type="image/png"
href="/favicons/favicon-light.png"
media="(prefers-color-scheme: dark)"
/>
<link
rel="icon"
type="image/svg+xml"
href="/favicons/favicon-light.svg"
media="(prefers-color-scheme: dark)"
/>
<link
rel="alternate icon"
type="image/png"
href="/favicons/favicon-dark.png"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
type="image/svg+xml"
href="/favicons/favicon-dark.svg"
media="(prefers-color-scheme: light)"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/index.tsx"></script>
</body>
</html>