Skip to content

Commit eb03ce2

Browse files
feat(www): WCAG fixes + axe gate + A11Y.md (#53)
Co-authored-by: Bradley Fernando <bradley.fernando@gmail.com>
1 parent 054d695 commit eb03ce2

15 files changed

Lines changed: 1237 additions & 62 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
branches: [main, develop]
66
pull_request:
7-
branches: [main]
7+
branches: [main, develop]
88

99
jobs:
1010
build:
@@ -18,4 +18,5 @@ jobs:
1818
cache: pnpm
1919
- run: pnpm install --frozen-lockfile
2020
- run: pnpm format:check
21+
- run: pnpm test:a11y
2122
- run: pnpm build

docs/A11Y.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# WCAG 2.1 AA Accessibility Audit
2+
3+
Issue: [wraith-protocol/www#21](https://github.com/wraith-protocol/www/issues/21)
4+
5+
Date: 2026-06-26
6+
7+
Scope: homepage and press page source audit, with implemented Critical and Serious fixes in this PR.
8+
9+
## Tools
10+
11+
- `vitest-axe` / `axe-core` smoke gate for the rendered homepage.
12+
- Keyboard navigation pass for skip link, desktop links, mobile menu, code tabs, comparison tabs, copy buttons, and press kit controls.
13+
- Color contrast review for small mono labels on `surface` and `surface-container` backgrounds.
14+
- Screen-reader semantics review for landmarks, heading hierarchy, tab widgets, icon/utility buttons, and live copy status messaging.
15+
- VoiceOver run-through checklist documented below for the corrected landmark, heading, tab, and button names.
16+
17+
## Findings
18+
19+
| Severity | WCAG 2.1 AA Criterion | Element / selector | Finding | Fix in this PR |
20+
| -------- | --------------------------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
21+
| Critical | 2.4.1 Bypass Blocks | `App`, page header/navigation | Keyboard users had no skip link to bypass the fixed navigation. | Added a visible-on-focus skip link targeting `main#main-content`. |
22+
| Serious | 2.4.7 Focus Visible | Global links and buttons | Interactive controls relied on browser defaults or visual hover states, which were inconsistent against the dark UI. | Added a global `:focus-visible` outline using the blue accent token. |
23+
| Serious | 1.4.3 Contrast (Minimum) | `.text-outline` small mono labels on dark backgrounds | The previous outline text color was too dim for repeated 9-13px labels. | Raised outline and outline-variant token contrast while preserving the dark visual system. |
24+
| Serious | 4.1.2 Name, Role, Value | `Header` mobile menu button and panel | Mobile menu state was not exposed, Escape did not dismiss it, and focus could leave the open menu unexpectedly. | Added `aria-expanded`, `aria-controls`, specific open/close labels, Escape dismiss, focus return, and a focus trap. |
25+
| Serious | 4.1.2 Name, Role, Value | `Hero` code sample tabs | Visual tabs were plain buttons without tab roles, selected state, or arrow-key navigation. | Added `tablist`, `tab`, `tabpanel`, `aria-selected`, `aria-controls`, roving tab index, and Arrow/Home/End key handling. |
26+
| Serious | 4.1.3 Status Messages | `Hero` and `Press` copy buttons | Copy actions changed visible text but did not reliably announce completion to assistive tech. | Added accessible button names and polite live-region copy status. |
27+
| Serious | 4.1.2 Name, Role, Value | `Compare` detail filter tabs | Comparison filters were visually tabbed but lacked tab semantics and keyboard tab behavior. | Added semantic tablist/tabpanel relationships and roving keyboard navigation. |
28+
| Serious | 1.3.1 Info and Relationships | `Compare` table row labels | Row labels used `scope="row"` on `td`, which is invalid table semantics. | Converted protocol row labels to `th scope="row"`. |
29+
| Serious | 2.5.3 Label in Name / 4.1.2 Name, Role, Value | `Press` brand color swatches | Swatches relied on `title` and visual color text, leaving button purpose ambiguous. | Added explicit labels such as `Copy Surface brand color #0e0e0e`. |
30+
| Minor | 1.1.1 Non-text Content | Header/footer logo images | Logo image alt text repeated adjacent Wraith text inside the same link/brand block. | Marked repeated logo images decorative with empty `alt`. |
31+
32+
## Follow-up Issues
33+
34+
| Severity | WCAG 2.1 AA Criterion | Element / selector | Recommendation |
35+
| -------- | --------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
36+
| Moderate | 1.3.1 Info and Relationships | Comparison table on narrow screens | Consider adding an off-screen caption that summarizes horizontal scrolling and comparison purpose. |
37+
| Moderate | 2.4.4 Link Purpose | Repeated external CTA links | Consider making repeated external CTA link purpose more specific where context is sparse. |
38+
| Minor | 2.3.3 Animation from Interactions | Decorative pulsing dots | Current reduced-motion rules cover reveal animations. Consider removing pulse animations under `prefers-reduced-motion` as a polish follow-up. |
39+
40+
## VoiceOver Run-through Notes
41+
42+
- Landmark order: skip link, banner/navigation, main content, footer.
43+
- Homepage heading structure: one `h1` followed by section-level `h2` headings.
44+
- Mobile menu button announces open/closed state and returns focus to the trigger on Escape.
45+
- Hero code examples announce as a tab group with selected file tab and associated code panel.
46+
- Comparison details announce as a tab group with selected filter and associated panel.
47+
- Copy controls have action-specific labels and announce successful copy through a polite status region.
48+
49+
## CI Gate
50+
51+
The homepage accessibility smoke gate is implemented in `src/__tests__/a11y.test.tsx` and runs with:
52+
53+
```bash
54+
pnpm test:a11y
55+
```
56+
57+
This test renders the homepage, runs axe, and verifies the primary mobile-menu and copy-control keyboard paths.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"preview": "vite preview",
10+
"test": "vitest run",
11+
"test:a11y": "vitest run src/__tests__/a11y.test.tsx",
1012
"format": "prettier --write .",
1113
"format:check": "prettier --check .",
1214
"prepare": "husky"
@@ -19,14 +21,20 @@
1921
"@commitlint/cli": "^20.5.0",
2022
"@commitlint/config-conventional": "^20.5.0",
2123
"@tailwindcss/vite": "^4.2.2",
24+
"@testing-library/jest-dom": "^6.9.1",
25+
"@testing-library/react": "^16.3.2",
26+
"@testing-library/user-event": "^14.6.1",
2227
"@types/react": "^19.2.14",
2328
"@types/react-dom": "^19.2.3",
2429
"@vitejs/plugin-react": "^6.0.1",
2530
"husky": "^9.1.7",
31+
"jsdom": "^29.1.1",
2632
"prettier": "^3.8.2",
2733
"tailwindcss": "^4.2.2",
2834
"typescript": "^6.0.2",
29-
"vite": "^8.0.8"
35+
"vite": "^8.0.8",
36+
"vitest": "^4.1.9",
37+
"vitest-axe": "^0.1.0"
3038
},
3139
"packageManager": "pnpm@10.28.2"
3240
}

0 commit comments

Comments
 (0)