Skip to content

Commit 883596a

Browse files
authored
Add Claude Skill for checking WCAG compliance (#1319)
1 parent 88e74ee commit 883596a

3 files changed

Lines changed: 331 additions & 3 deletions

File tree

.claude/skills/code-review-react/skill.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Stick to the checklist below for every applicable file and mode. Apply only the
2020
## Checklist
2121
See [.agents/review-checklists/common.md](../../../.agents/review-checklists/common.md) for reviewer priority and standard review format, and [.agents/review-checklists/react/code-quality.md](../../../.agents/review-checklists/react/code-quality.md), [.agents/review-checklists/react/performance.md](../../../.agents/review-checklists/react/performance.md), [.agents/review-checklists/react/business-logic.md](../../../.agents/review-checklists/react/business-logic.md) for the living checklist split by category—treat it as the canonical set of rules to follow.
2222

23+
Additionally, check for WCAG 2.2 Level AA accessibility violations using [wcag-22-checklist.md](../wcag-compliance/wcag-22-checklist.md). Use category **Accessibility** for these findings. Prioritize urgent WCAG criteria (missing alt text, keyboard traps, no focus indicators, missing form labels, broken ARIA) alongside Correctness-level issues.
24+
2325
Use the rule's `Urgency` to place findings in the "urgent issues" vs "suggestions" sections.
2426

2527
## Review Process
@@ -66,7 +68,7 @@ unchanged code only if they directly interact with or are affected by the change
6668
1. Open the relevant component/module. Gather all lines.
6769
2. For each applicable checklist rule, evaluate the code against the rule text, confidence threshold, and exceptions/false positives before deciding to flag it.
6870
3. For each confirmed violation, capture evidence (exact snippet and/or file/line), record the rule's primary category, and note confidence briefly.
69-
4. Compose the review section per the template below. Group findings by **Urgency** section first (urgent issues, then suggestions). Within each section, order findings by the checklist primary category priority: **Correctness**, then **Maintainability**, then **Style**.
71+
4. Compose the review section per the template below. Group findings by **Urgency** section first (urgent issues, then suggestions). Within each section, order findings by the checklist primary category priority: **Correctness**, then **Accessibility**, then **Maintainability**, then **Style**.
7072

7173
## Required output
7274
When invoked, the response must exactly follow one of the two templates:
@@ -79,7 +81,7 @@ Found <N> urgent issues that need to be fixed:
7981
## 1 <brief description of bug>
8082
FilePath: <path> line <line>
8183
Evidence: <relevant code snippet or pointer>
82-
Category: <Correctness | Maintainability | Style>
84+
Category: <Correctness | Accessibility | Maintainability | Style>
8385
Confidence: <high | medium | low> - <brief justification>
8486
Exceptions checked: <none apply | brief exception note>
8587
@@ -95,7 +97,7 @@ Found <M> suggestions for improvement:
9597
## 1 <brief description of suggestion>
9698
FilePath: <path> line <line>
9799
Evidence: <relevant code snippet or pointer>
98-
Category: <Correctness | Maintainability | Style>
100+
Category: <Correctness | Accessibility | Maintainability | Style>
99101
Confidence: <high | medium | low> - <brief justification>
100102
Exceptions checked: <none apply | brief exception note>
101103
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
name: wcag-compliance
3+
description: "Review frontend code for WCAG 2.2 Level AA accessibility compliance. Checks semantic HTML, ARIA usage, keyboard navigation, color contrast, focus management, and more. Supports --full flag for complete file/directory review; defaults to staged changes when a path is provided."
4+
---
5+
6+
# WCAG 2.2 Accessibility Compliance Review
7+
8+
## Intent
9+
Use this skill whenever the user asks to check accessibility or WCAG compliance of frontend code (`.tsx`, `.ts`, `.js`, `.jsx`, `.scss`, `.css`, `.jsp`, `.jspf` files). Support three review modes:
10+
11+
1. **Pending-change review** -- bare invocation with no arguments; inspects staged/working-tree
12+
files slated for commit across all repos.
13+
2. **Path review (default)** -- a file or directory path is provided (no flag); reviews only the
14+
git staged/working-tree changes for that path.
15+
3. **Full review** -- a file or directory path is provided with `--full`; reviews the entire file
16+
contents (or all matching files in a directory) regardless of git status.
17+
18+
Apply only the WCAG 2.2 Level AA checklist below. Focus on issues that can be detected through static code review.
19+
20+
## Checklist
21+
See [wcag-22-checklist.md](wcag-22-checklist.md) for the full set of criteria organized by principle.
22+
23+
Each rule has an **Urgency** level:
24+
- **urgent** -- Violations that block users from accessing content or functionality.
25+
- **suggestion** -- Improvements that enhance the experience but don't fully block access.
26+
27+
## Review Process
28+
29+
**Argument parsing:**
30+
31+
Parse the invocation arguments to extract:
32+
- An optional flag: `--full`
33+
- An optional path: a file path or directory path
34+
35+
**File discovery:**
36+
37+
- **No path, no flag (bare invocation):** Pending-change review. Discover nested repos by
38+
running `find server/modules -maxdepth 2 -name ".git" -type d` from the workspace root,
39+
then for each discovered repo (and the top-level root) run `git diff --cached --name-only`
40+
and `git diff --name-only`. Aggregate all results, filtering to applicable extensions
41+
(`.tsx`, `.ts`, `.js`, `.jsx`, `.scss`, `.css`, `.jsp`, `.jspf`).
42+
43+
- **Path provided (no `--full` flag -- default):** Determine the git root via
44+
`git -C <path> rev-parse --show-toplevel`.
45+
- *File path:* Run `git diff --cached -- <file>` and `git diff -- <file>`. If there are
46+
no changes, report "No staged or working-tree changes found for `<file>`." and stop.
47+
If there are changes, proceed to review.
48+
- *Directory path:* Run `git diff --cached --name-only -- <dir>` and
49+
`git diff --name-only -- <dir>`. Filter to applicable extensions. If no changed files
50+
are found, report "No staged or working-tree changes found under `<dir>`." and stop.
51+
52+
- **Path + `--full`:** Review the entire contents regardless of git status.
53+
- *File path:* Use the file directly -- no git discovery needed.
54+
- *Directory path:* Find all files matching applicable extensions under the directory
55+
(using glob/find). Review every matching file.
56+
57+
- **`--full` with no path:** Ask the user to provide a file or directory path.
58+
59+
**Review scope when reviewing staged changes (default mode):**
60+
61+
When reviewing staged changes, read the full file for context but **focus the review on changed
62+
lines and their immediate surroundings**. Use the diff output to identify which sections
63+
changed, then apply the checklist rules primarily to those sections. Still flag issues in
64+
unchanged code only if they directly interact with or are affected by the changes.
65+
66+
**Multi-file grouping:** When reviewing multiple files, group all findings together by urgency section (urgent issues first, then suggestions), not per-file. Include the file path in each finding's `FilePath` field.
67+
68+
1. Open the relevant file(s). Gather all lines.
69+
2. For each applicable checklist rule, evaluate the code against the rule text.
70+
3. For each confirmed violation, capture evidence (exact snippet and/or file/line), record the WCAG criterion, and note confidence.
71+
4. Compose the review per the template below.
72+
73+
## Required output
74+
When invoked, the response must exactly follow one of the two templates:
75+
76+
### Template A (any findings)
77+
```
78+
# Accessibility review (WCAG 2.2 AA)
79+
Found <N> urgent issues that need to be fixed:
80+
81+
## 1 <brief description>
82+
FilePath: <path> line <line>
83+
WCAG Criterion: <number and name, e.g. "1.1.1 Non-text Content">
84+
Evidence: <relevant code snippet or pointer>
85+
Confidence: <high | medium | low> - <brief justification>
86+
87+
88+
### Suggested fix
89+
<brief description of suggested fix, with code example if helpful>
90+
91+
---
92+
... (repeat for each urgent issue) ...
93+
94+
Found <M> suggestions for improvement:
95+
96+
## 1 <brief description>
97+
FilePath: <path> line <line>
98+
WCAG Criterion: <number and name>
99+
Evidence: <relevant code snippet or pointer>
100+
Confidence: <high | medium | low> - <brief justification>
101+
102+
103+
### Suggested fix
104+
<brief description of suggested fix>
105+
106+
---
107+
108+
... (repeat for each suggestion) ...
109+
```
110+
111+
If there are no urgent issues, omit that section. If there are no suggestions, omit that section.
112+
113+
Always list every urgent issue -- never cap or truncate them. If there are more than 10 suggestions, summarize as "10+ suggestions" and output the first 10.
114+
115+
Don't compress the blank lines between sections; keep them as-is for readability.
116+
117+
If you use Template A and at least one issue requires code changes, append a brief follow-up question after the structured output asking whether the user wants you to apply the suggested fix(es).
118+
119+
### Template B (no issues)
120+
```
121+
# Accessibility review (WCAG 2.2 AA)
122+
No issues found.
123+
```
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# WCAG 2.2 Level AA -- Static Code Review Checklist
2+
3+
This checklist covers WCAG 2.2 Level AA success criteria that can be detected through code review. Criteria that require runtime testing (e.g., timing, audio descriptions) are excluded.
4+
5+
---
6+
7+
## Principle 1: Perceivable
8+
9+
### 1.1.1 Non-text Content (Level A)
10+
**Urgency: urgent**
11+
- `<img>` elements must have an `alt` attribute. Decorative images should use `alt=""` or `role="presentation"`.
12+
- Icon-only buttons/links must have an accessible name (`aria-label`, `aria-labelledby`, or visually hidden text).
13+
- `<svg>` elements used as content must have `role="img"` and an accessible name (`aria-label` or `<title>`).
14+
- Font icon elements (e.g., `<i className="fa fa-..."`) used as interactive controls must have an accessible name.
15+
- **Exception:** Purely decorative elements that don't convey information.
16+
17+
### 1.3.1 Info and Relationships (Level A)
18+
**Urgency: urgent**
19+
- Use semantic HTML elements (`<nav>`, `<main>`, `<header>`, `<footer>`, `<section>`, `<article>`) instead of generic `<div>` for landmarks.
20+
- Headings (`<h1>`-`<h6>`) must follow a logical hierarchy -- no skipped levels.
21+
- Form inputs must have associated `<label>` elements (via `htmlFor`/`id`) or `aria-label`/`aria-labelledby`.
22+
- Data tables must use `<th>` with `scope` attributes. Do not use tables for layout.
23+
- Related form controls should be grouped with `<fieldset>` and `<legend>`.
24+
- Lists of items should use `<ul>`, `<ol>`, or `<dl>` -- not styled `<div>` sequences.
25+
26+
### 1.3.2 Meaningful Sequence (Level A)
27+
**Urgency: suggestion**
28+
- DOM order should match the visual reading order. Avoid CSS that reorders content (`order`, `flex-direction: row-reverse`) in ways that break reading sequence.
29+
30+
### 1.3.4 Orientation (Level AA)
31+
**Urgency: suggestion**
32+
- Do not restrict display to a single orientation via CSS or JS unless essential.
33+
34+
### 1.3.5 Identify Input Purpose (Level AA)
35+
**Urgency: suggestion**
36+
- Form fields for personal data (name, email, phone, address, etc.) should have appropriate `autoComplete` attributes.
37+
38+
### 1.4.1 Use of Color (Level A)
39+
**Urgency: urgent**
40+
- Color must not be the only visual means of conveying information (e.g., error states, required fields, status). Provide text, icons, or patterns as well.
41+
42+
### 1.4.3 Contrast (Minimum) (Level AA)
43+
**Urgency: urgent**
44+
- Text color against its background must meet 4.5:1 ratio for normal text, 3:1 for large text (18pt+ or 14pt+ bold).
45+
- Check hardcoded color values in CSS/SCSS and inline styles. Flag combinations that are visually likely to fail (e.g., light gray on white).
46+
- **Note:** Exact contrast can only be verified with a tool; flag suspicious values for manual check.
47+
48+
### 1.4.4 Resize Text (Level AA)
49+
**Urgency: suggestion**
50+
- Text sizes should use relative units (`rem`, `em`, `%`) rather than fixed `px` for body text.
51+
- Layouts should not break at 200% zoom. Avoid fixed-height containers with `overflow: hidden` on text content.
52+
53+
### 1.4.11 Non-text Contrast (Level AA)
54+
**Urgency: suggestion**
55+
- UI components (form controls, buttons) and meaningful graphics must have at least 3:1 contrast against adjacent colors.
56+
57+
### 1.4.13 Content on Hover or Focus (Level AA)
58+
**Urgency: suggestion**
59+
- Tooltips/popovers shown on hover must also be dismissible (Escape key), hoverable (user can move pointer to the tooltip), and persistent (don't disappear while the user is interacting).
60+
61+
---
62+
63+
## Principle 2: Operable
64+
65+
### 2.1.1 Keyboard (Level A)
66+
**Urgency: urgent**
67+
- All interactive elements must be keyboard accessible. `onClick` on non-interactive elements (`<div>`, `<span>`) requires `onKeyDown`/`onKeyUp`, `tabIndex="0"`, and `role`.
68+
- Prefer semantic elements (`<button>`, `<a>`, `<input>`) over ARIA-enhanced `<div>`s.
69+
- Drag-and-drop must have a keyboard alternative.
70+
- Custom widgets must handle expected key interactions (e.g., arrow keys for menus/tabs, Space/Enter for buttons).
71+
72+
### 2.1.2 No Keyboard Trap (Level A)
73+
**Urgency: urgent**
74+
- Modal dialogs must trap focus *within* the modal but allow dismissal via Escape.
75+
- Focus must not get stuck in any component. Verify that custom focus management doesn't prevent tabbing away.
76+
77+
### 2.4.1 Bypass Blocks (Level A)
78+
**Urgency: suggestion**
79+
- Pages with repeated navigation should provide a "skip to main content" link or use landmark regions.
80+
81+
### 2.4.2 Page Titled (Level A)
82+
**Urgency: suggestion**
83+
- Each page/view should set a descriptive `<title>` or use `document.title`.
84+
85+
### 2.4.3 Focus Order (Level A)
86+
**Urgency: urgent**
87+
- `tabIndex` values greater than 0 disrupt natural focus order -- flag any `tabIndex` > 0.
88+
- Tab order must follow a logical sequence through the page.
89+
90+
### 2.4.4 Link Purpose (Level A)
91+
**Urgency: suggestion**
92+
- Link text must describe the destination. Flag "click here", "here", "read more" without context.
93+
- If link text is generic, `aria-label` or `aria-describedby` should provide context.
94+
95+
### 2.4.6 Headings and Labels (Level AA)
96+
**Urgency: suggestion**
97+
- Headings and labels must be descriptive. Flag empty headings or labels.
98+
99+
### 2.4.7 Focus Visible (Level AA)
100+
**Urgency: urgent**
101+
- Do not remove focus indicators. Flag `outline: none`, `outline: 0`, or `:focus { outline: none }` without a replacement focus style.
102+
- Custom focus styles must be clearly visible.
103+
104+
### 2.4.11 Focus Not Obscured (Minimum) (Level AA) -- NEW in 2.2
105+
**Urgency: urgent**
106+
- When a component receives focus, it must not be entirely hidden by other content (e.g., sticky headers, footers, overlays).
107+
- Check for `position: fixed`/`sticky` elements that could cover focused items. Ensure `scroll-padding` or `scroll-margin` accounts for sticky elements.
108+
109+
### 2.4.13 Focus Appearance (Level AAA, but recommended)
110+
**Urgency: suggestion**
111+
- Custom focus indicators should have at least a 2px solid outline with 3:1 contrast against adjacent colors.
112+
113+
### 2.5.7 Dragging Movements (Level AA) -- NEW in 2.2
114+
**Urgency: urgent**
115+
- Any functionality that uses dragging must provide a single-pointer alternative (e.g., up/down buttons to reorder, click-to-select then click-to-place).
116+
- **Exception:** Dragging is essential to the function (rare).
117+
118+
### 2.5.8 Target Size (Minimum) (Level AA) -- NEW in 2.2
119+
**Urgency: suggestion**
120+
- Interactive targets should be at least 24x24 CSS pixels, or have sufficient spacing so the target + spacing meets 24px.
121+
- **Exceptions:** Inline text links, targets where the size is determined by the user agent (e.g., default checkboxes), essential presentation.
122+
123+
---
124+
125+
## Principle 3: Understandable
126+
127+
### 3.1.1 Language of Page (Level A)
128+
**Urgency: suggestion**
129+
- HTML element should have a `lang` attribute (`<html lang="en">`).
130+
131+
### 3.1.2 Language of Parts (Level AA)
132+
**Urgency: suggestion**
133+
- Content in a different language than the page should use `lang` attribute on its container.
134+
135+
### 3.2.1 On Focus (Level A)
136+
**Urgency: urgent**
137+
- Focus must not trigger a change of context (e.g., page navigation, form submission, opening a new window).
138+
139+
### 3.2.2 On Input (Level A)
140+
**Urgency: urgent**
141+
- Changing a form control value must not automatically trigger a change of context unless the user is informed beforehand.
142+
- Flag `onChange` handlers that submit forms or navigate without user confirmation.
143+
144+
### 3.3.1 Error Identification (Level A)
145+
**Urgency: urgent**
146+
- Form errors must be described in text, not just color. Error messages must identify which field has the error.
147+
- Error messages must be programmatically associated with their inputs (`aria-describedby`, `aria-errormessage`, or `aria-invalid`).
148+
149+
### 3.3.2 Labels or Instructions (Level A)
150+
**Urgency: urgent**
151+
- Form inputs must have visible labels. Placeholder text alone is not sufficient as a label.
152+
- Required fields must be indicated in a way that doesn't rely solely on color.
153+
154+
### 3.3.3 Error Suggestion (Level AA)
155+
**Urgency: suggestion**
156+
- When an input error is detected, provide a suggestion for correction if possible.
157+
158+
### 3.3.7 Redundant Entry (Level A) -- NEW in 2.2
159+
**Urgency: suggestion**
160+
- Do not require users to re-enter information they have already provided in the same process/session.
161+
- **Exceptions:** Re-entering for security purposes, or when previously entered info is no longer valid.
162+
163+
### 3.3.8 Accessible Authentication (Minimum) (Level AA) -- NEW in 2.2
164+
**Urgency: urgent**
165+
- Authentication must not require cognitive function tests (e.g., CAPTCHA, puzzle) unless an alternative is provided (e.g., object recognition, personal content).
166+
- Allow pasting into password fields. Do not block password managers.
167+
168+
---
169+
170+
## Principle 4: Robust
171+
172+
### 4.1.2 Name, Role, Value (Level A)
173+
**Urgency: urgent**
174+
- Custom components must expose correct ARIA roles, states, and properties.
175+
- `aria-expanded`, `aria-selected`, `aria-checked`, `aria-pressed` must accurately reflect component state.
176+
- `aria-hidden="true"` must not be set on focusable or interactive elements.
177+
- `role` values must be valid WAI-ARIA roles.
178+
- IDs referenced by `aria-labelledby`, `aria-describedby`, `aria-controls`, etc. must exist in the DOM.
179+
180+
### 4.1.3 Status Messages (Level AA)
181+
**Urgency: suggestion**
182+
- Status messages (success, error, loading, progress) that don't receive focus must use `role="status"`, `role="alert"`, or `aria-live` regions so screen readers announce them.
183+
- Use `aria-live="polite"` for non-urgent updates, `aria-live="assertive"` for critical alerts.
184+
185+
---
186+
187+
## LabKey-Specific Patterns
188+
189+
These patterns are common in the LabKey codebase and deserve extra attention:
190+
191+
### React Components (`@labkey/components`, `@labkey/premium`)
192+
- Verify `Alert` components use appropriate ARIA roles.
193+
- Check `Modal`/`ModalDialog` components trap focus and are dismissible via Escape.
194+
- Ensure `Grid`/`QueryGrid` table components use proper `<table>` semantics with headers.
195+
- Check custom dropdown/select components for keyboard navigation (arrow keys, Escape, Enter).
196+
197+
### JSP Pages
198+
- Verify `<labkey:form>` and `<labkey:input>` render with proper label associations.
199+
- Check `<labkey:link>` and `<labkey:button>` produce accessible HTML.
200+
201+
### ExtJS Components
202+
- ExtJS components often lack accessibility. Flag custom ExtJS widgets that have no ARIA markup.
203+
- Verify ExtJS modals/windows are keyboard dismissible.

0 commit comments

Comments
 (0)