real-prototypes-skill 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/agent-browser-skill/SKILL.md +252 -0
- package/.claude/skills/real-prototypes-skill/.gitignore +188 -0
- package/.claude/skills/real-prototypes-skill/ACCESSIBILITY.md +668 -0
- package/.claude/skills/real-prototypes-skill/INSTALL.md +259 -0
- package/.claude/skills/real-prototypes-skill/LICENSE +21 -0
- package/.claude/skills/real-prototypes-skill/PUBLISH.md +310 -0
- package/.claude/skills/real-prototypes-skill/QUICKSTART.md +240 -0
- package/.claude/skills/real-prototypes-skill/README.md +442 -0
- package/.claude/skills/real-prototypes-skill/SKILL.md +375 -0
- package/.claude/skills/real-prototypes-skill/capture/capture-engine.js +1153 -0
- package/.claude/skills/real-prototypes-skill/capture/config.schema.json +170 -0
- package/.claude/skills/real-prototypes-skill/cli.js +596 -0
- package/.claude/skills/real-prototypes-skill/docs/TROUBLESHOOTING.md +278 -0
- package/.claude/skills/real-prototypes-skill/docs/schemas/capture-config.md +167 -0
- package/.claude/skills/real-prototypes-skill/docs/schemas/design-tokens.md +183 -0
- package/.claude/skills/real-prototypes-skill/docs/schemas/manifest.md +169 -0
- package/.claude/skills/real-prototypes-skill/examples/CLAUDE.md.example +73 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/CLAUDE.md +136 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/FEATURES.md +222 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/README.md +82 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/design-tokens.json +87 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/homepage-viewport.png +0 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/prototype-chatbot-final.png +0 -0
- package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/prototype-fullpage-v2.png +0 -0
- package/.claude/skills/real-prototypes-skill/references/accessibility-fixes.md +298 -0
- package/.claude/skills/real-prototypes-skill/references/accessibility-report.json +253 -0
- package/.claude/skills/real-prototypes-skill/scripts/CAPTURE-ENHANCEMENTS.md +344 -0
- package/.claude/skills/real-prototypes-skill/scripts/IMPLEMENTATION-SUMMARY.md +517 -0
- package/.claude/skills/real-prototypes-skill/scripts/QUICK-START.md +229 -0
- package/.claude/skills/real-prototypes-skill/scripts/QUICKSTART-layout-analysis.md +148 -0
- package/.claude/skills/real-prototypes-skill/scripts/README-analyze-layout.md +407 -0
- package/.claude/skills/real-prototypes-skill/scripts/analyze-layout.js +880 -0
- package/.claude/skills/real-prototypes-skill/scripts/capture-platform.js +203 -0
- package/.claude/skills/real-prototypes-skill/scripts/comprehensive-capture.js +597 -0
- package/.claude/skills/real-prototypes-skill/scripts/create-manifest.js +338 -0
- package/.claude/skills/real-prototypes-skill/scripts/enterprise-pipeline.js +428 -0
- package/.claude/skills/real-prototypes-skill/scripts/extract-tokens.js +468 -0
- package/.claude/skills/real-prototypes-skill/scripts/full-site-capture.js +738 -0
- package/.claude/skills/real-prototypes-skill/scripts/generate-tailwind-config.js +296 -0
- package/.claude/skills/real-prototypes-skill/scripts/integrate-accessibility.sh +161 -0
- package/.claude/skills/real-prototypes-skill/scripts/manifest-schema.json +302 -0
- package/.claude/skills/real-prototypes-skill/scripts/setup-prototype.sh +167 -0
- package/.claude/skills/real-prototypes-skill/scripts/test-analyze-layout.js +338 -0
- package/.claude/skills/real-prototypes-skill/scripts/test-validation.js +307 -0
- package/.claude/skills/real-prototypes-skill/scripts/validate-accessibility.js +598 -0
- package/.claude/skills/real-prototypes-skill/scripts/validate-manifest.js +499 -0
- package/.claude/skills/real-prototypes-skill/scripts/validate-output.js +361 -0
- package/.claude/skills/real-prototypes-skill/scripts/validate-prerequisites.js +319 -0
- package/.claude/skills/real-prototypes-skill/scripts/verify-layout-analysis.sh +77 -0
- package/.claude/skills/real-prototypes-skill/templates/dashboard-widget.tsx.template +91 -0
- package/.claude/skills/real-prototypes-skill/templates/data-table.tsx.template +193 -0
- package/.claude/skills/real-prototypes-skill/templates/form-section.tsx.template +250 -0
- package/.claude/skills/real-prototypes-skill/templates/modal-dialog.tsx.template +239 -0
- package/.claude/skills/real-prototypes-skill/templates/nav-item.tsx.template +265 -0
- package/.claude/skills/real-prototypes-skill/validation/validation-engine.js +559 -0
- package/.env.example +74 -0
- package/LICENSE +21 -0
- package/README.md +444 -0
- package/bin/cli.js +319 -0
- package/package.json +59 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
# Accessibility Quick Reference
|
|
2
|
+
|
|
3
|
+
## WCAG 2.1 AA Compliance Guide
|
|
4
|
+
|
|
5
|
+
This guide provides quick reference for ensuring all generated prototypes meet accessibility standards.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
### 1. Run Validation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd prototype
|
|
15
|
+
npm run validate:a11y
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Review Reports
|
|
19
|
+
|
|
20
|
+
- **JSON Report:** `references/accessibility-report.json` - Machine-readable
|
|
21
|
+
- **Markdown Docs:** `references/accessibility-fixes.md` - Human-readable
|
|
22
|
+
|
|
23
|
+
### 3. Fix Issues
|
|
24
|
+
|
|
25
|
+
See "Common Fixes" section below
|
|
26
|
+
|
|
27
|
+
### 4. Re-validate
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run validate:a11y
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## WCAG 2.1 AA Requirements
|
|
36
|
+
|
|
37
|
+
### Color Contrast
|
|
38
|
+
|
|
39
|
+
| Text Type | Minimum Ratio | Example |
|
|
40
|
+
|-----------|---------------|---------|
|
|
41
|
+
| Normal text (< 18pt) | 4.5:1 | Black on white: 21:1 ✅ |
|
|
42
|
+
| Large text (≥ 18pt or ≥ 14pt bold) | 3.0:1 | Gray on white: 3.5:1 ✅ |
|
|
43
|
+
| UI components | 3.0:1 | Border contrast |
|
|
44
|
+
|
|
45
|
+
**Tool:** [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
|
46
|
+
|
|
47
|
+
### Keyboard Navigation
|
|
48
|
+
|
|
49
|
+
**Requirements:**
|
|
50
|
+
- All interactive elements keyboard accessible
|
|
51
|
+
- Logical tab order
|
|
52
|
+
- No keyboard traps
|
|
53
|
+
- Visible focus indicators
|
|
54
|
+
|
|
55
|
+
**Keys:**
|
|
56
|
+
- `Tab` - Navigate forward
|
|
57
|
+
- `Shift+Tab` - Navigate backward
|
|
58
|
+
- `Enter/Space` - Activate buttons/links
|
|
59
|
+
- `Escape` - Close modals/dialogs
|
|
60
|
+
- `Arrow keys` - Navigate menus/tabs
|
|
61
|
+
|
|
62
|
+
### ARIA Labels
|
|
63
|
+
|
|
64
|
+
**All interactive elements need accessible names:**
|
|
65
|
+
|
|
66
|
+
| Element | Required |
|
|
67
|
+
|---------|----------|
|
|
68
|
+
| Button with text | Text content |
|
|
69
|
+
| Icon button | `aria-label` |
|
|
70
|
+
| Link | Text content or `aria-label` |
|
|
71
|
+
| Form input | Associated `<label>` or `aria-label` |
|
|
72
|
+
| Custom widget | Appropriate ARIA role and attributes |
|
|
73
|
+
|
|
74
|
+
### Focus Indicators
|
|
75
|
+
|
|
76
|
+
**Requirements:**
|
|
77
|
+
- Visible on all focusable elements
|
|
78
|
+
- Minimum 3:1 contrast with background
|
|
79
|
+
- Not removed unless replaced
|
|
80
|
+
|
|
81
|
+
**Tailwind pattern:**
|
|
82
|
+
```typescript
|
|
83
|
+
focus:ring-2 focus:ring-platform-primary focus:ring-offset-2
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Semantic HTML
|
|
87
|
+
|
|
88
|
+
**Use proper elements:**
|
|
89
|
+
- `<button>` for buttons (not `<div onClick>`)
|
|
90
|
+
- `<a href>` for links
|
|
91
|
+
- `<h1>` to `<h6>` for headings (maintain hierarchy)
|
|
92
|
+
- `<nav>`, `<main>`, `<footer>` for landmarks
|
|
93
|
+
- `<ul>`, `<ol>` for lists
|
|
94
|
+
- `<table>` for tabular data
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Common Fixes
|
|
99
|
+
|
|
100
|
+
### Fix 1: Low Contrast Text
|
|
101
|
+
|
|
102
|
+
**Problem:**
|
|
103
|
+
```typescript
|
|
104
|
+
<p className="text-gray-400">Low contrast</p>
|
|
105
|
+
// Contrast: 2.8:1 ❌
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Solution:**
|
|
109
|
+
```typescript
|
|
110
|
+
<p className="text-gray-600">Improved contrast</p>
|
|
111
|
+
// Contrast: 4.6:1 ✅
|
|
112
|
+
// Visual change: ~5% darker
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### Fix 2: Missing Focus Indicator
|
|
118
|
+
|
|
119
|
+
**Problem:**
|
|
120
|
+
```typescript
|
|
121
|
+
<button className="bg-blue-500 text-white">
|
|
122
|
+
Click me
|
|
123
|
+
</button>
|
|
124
|
+
// No visible focus state ❌
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Solution:**
|
|
128
|
+
```typescript
|
|
129
|
+
<button className="bg-blue-500 text-white focus:ring-2 focus:ring-blue-600 focus:ring-offset-2">
|
|
130
|
+
Click me
|
|
131
|
+
</button>
|
|
132
|
+
// Visible focus ring ✅
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Fix 3: Icon Button Without Label
|
|
138
|
+
|
|
139
|
+
**Problem:**
|
|
140
|
+
```typescript
|
|
141
|
+
<button>
|
|
142
|
+
<IconX />
|
|
143
|
+
</button>
|
|
144
|
+
// No accessible name ❌
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Solution:**
|
|
148
|
+
```typescript
|
|
149
|
+
<button aria-label="Close dialog">
|
|
150
|
+
<IconX aria-hidden="true" />
|
|
151
|
+
</button>
|
|
152
|
+
// Screen reader announces "Close dialog" ✅
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Fix 4: Unlabeled Form Input
|
|
158
|
+
|
|
159
|
+
**Problem:**
|
|
160
|
+
```typescript
|
|
161
|
+
<label>Email</label>
|
|
162
|
+
<input type="email" />
|
|
163
|
+
// Not programmatically associated ❌
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Solution:**
|
|
167
|
+
```typescript
|
|
168
|
+
<label htmlFor="email">Email</label>
|
|
169
|
+
<input
|
|
170
|
+
id="email"
|
|
171
|
+
type="email"
|
|
172
|
+
aria-required="true"
|
|
173
|
+
/>
|
|
174
|
+
// Associated via htmlFor/id ✅
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Fix 5: Non-semantic Interactive Element
|
|
180
|
+
|
|
181
|
+
**Problem:**
|
|
182
|
+
```typescript
|
|
183
|
+
<div onClick={handleClick}>
|
|
184
|
+
Click me
|
|
185
|
+
</div>
|
|
186
|
+
// Not keyboard accessible ❌
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Solution:**
|
|
190
|
+
```typescript
|
|
191
|
+
<button onClick={handleClick}>
|
|
192
|
+
Click me
|
|
193
|
+
</button>
|
|
194
|
+
// Keyboard accessible ✅
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Fix 6: Missing Alt Text
|
|
200
|
+
|
|
201
|
+
**Problem:**
|
|
202
|
+
```typescript
|
|
203
|
+
<img src="logo.png" />
|
|
204
|
+
// Missing alt ❌
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Solution (decorative):**
|
|
208
|
+
```typescript
|
|
209
|
+
<img src="logo.png" alt="" />
|
|
210
|
+
// Empty alt for decorative ✅
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Solution (meaningful):**
|
|
214
|
+
```typescript
|
|
215
|
+
<img src="chart.png" alt="Sales growth chart showing 25% increase in Q4" />
|
|
216
|
+
// Descriptive alt text ✅
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### Fix 7: Form Validation Without ARIA
|
|
222
|
+
|
|
223
|
+
**Problem:**
|
|
224
|
+
```typescript
|
|
225
|
+
<input type="email" />
|
|
226
|
+
{error && <p>{error}</p>}
|
|
227
|
+
// Error not linked to input ❌
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Solution:**
|
|
231
|
+
```typescript
|
|
232
|
+
<input
|
|
233
|
+
type="email"
|
|
234
|
+
aria-invalid={!!error}
|
|
235
|
+
aria-describedby={error ? "email-error" : undefined}
|
|
236
|
+
/>
|
|
237
|
+
{error && (
|
|
238
|
+
<p id="email-error" role="alert">
|
|
239
|
+
{error}
|
|
240
|
+
</p>
|
|
241
|
+
)}
|
|
242
|
+
// Error announced by screen reader ✅
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### Fix 8: Heading Hierarchy Skip
|
|
248
|
+
|
|
249
|
+
**Problem:**
|
|
250
|
+
```typescript
|
|
251
|
+
<h1>Main Title</h1>
|
|
252
|
+
<h3>Subtitle</h3>
|
|
253
|
+
// Skips h2 ❌
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Solution:**
|
|
257
|
+
```typescript
|
|
258
|
+
<h1>Main Title</h1>
|
|
259
|
+
<h2>Subtitle</h2>
|
|
260
|
+
// Proper hierarchy ✅
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Color Adjustment Strategy
|
|
266
|
+
|
|
267
|
+
When fixing contrast issues, follow these steps:
|
|
268
|
+
|
|
269
|
+
### Step 1: Measure Current Contrast
|
|
270
|
+
|
|
271
|
+
Use browser DevTools or WebAIM Contrast Checker
|
|
272
|
+
|
|
273
|
+
### Step 2: Determine Required Ratio
|
|
274
|
+
|
|
275
|
+
- Normal text: 4.5:1
|
|
276
|
+
- Large text: 3.0:1
|
|
277
|
+
- UI components: 3.0:1
|
|
278
|
+
|
|
279
|
+
### Step 3: Adjust Minimally
|
|
280
|
+
|
|
281
|
+
**Goal:** Meet requirements with < 5% visual change
|
|
282
|
+
|
|
283
|
+
**Tailwind adjustment examples:**
|
|
284
|
+
```typescript
|
|
285
|
+
// Too light
|
|
286
|
+
text-gray-300 → text-gray-400 (one step darker)
|
|
287
|
+
text-gray-400 → text-gray-500 (one step darker)
|
|
288
|
+
|
|
289
|
+
// Too dark
|
|
290
|
+
text-gray-700 → text-gray-600 (one step lighter)
|
|
291
|
+
text-gray-800 → text-gray-700 (one step lighter)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Step 4: Re-test
|
|
295
|
+
|
|
296
|
+
Verify new contrast ratio meets requirements
|
|
297
|
+
|
|
298
|
+
### Step 5: Document
|
|
299
|
+
|
|
300
|
+
Add note to `accessibility-fixes.md` explaining the change
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## ESLint Rules
|
|
305
|
+
|
|
306
|
+
### Most Common Issues Caught
|
|
307
|
+
|
|
308
|
+
1. **jsx-a11y/alt-text**
|
|
309
|
+
- Missing alt on images
|
|
310
|
+
- Fix: Add `alt=""` (decorative) or descriptive text
|
|
311
|
+
|
|
312
|
+
2. **jsx-a11y/click-events-have-key-events**
|
|
313
|
+
- Click handler without keyboard handler
|
|
314
|
+
- Fix: Add `onKeyDown` or use `<button>`
|
|
315
|
+
|
|
316
|
+
3. **jsx-a11y/label-has-associated-control**
|
|
317
|
+
- Form input without label
|
|
318
|
+
- Fix: Add `htmlFor` to label or `aria-label` to input
|
|
319
|
+
|
|
320
|
+
4. **jsx-a11y/no-static-element-interactions**
|
|
321
|
+
- Interactive div/span
|
|
322
|
+
- Fix: Use `<button>` or add `role` and keyboard handlers
|
|
323
|
+
|
|
324
|
+
5. **jsx-a11y/anchor-is-valid**
|
|
325
|
+
- Link without href or with invalid href
|
|
326
|
+
- Fix: Add valid `href` or use `<button>`
|
|
327
|
+
|
|
328
|
+
### Running ESLint
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Check all files
|
|
332
|
+
npm run lint:a11y
|
|
333
|
+
|
|
334
|
+
# Check specific file
|
|
335
|
+
npx eslint src/components/MyComponent.tsx
|
|
336
|
+
|
|
337
|
+
# Auto-fix where possible
|
|
338
|
+
npx eslint src/components/MyComponent.tsx --fix
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Testing Checklist
|
|
344
|
+
|
|
345
|
+
### Automated Tests
|
|
346
|
+
|
|
347
|
+
- [ ] Run `npm run validate:a11y` - passes with 0 errors
|
|
348
|
+
- [ ] Run `npm run lint:a11y` - no accessibility warnings
|
|
349
|
+
- [ ] Lighthouse audit - score ≥ 90
|
|
350
|
+
- [ ] axe DevTools - no violations
|
|
351
|
+
|
|
352
|
+
### Manual Keyboard Tests
|
|
353
|
+
|
|
354
|
+
- [ ] Tab through all interactive elements
|
|
355
|
+
- [ ] All elements reachable via keyboard
|
|
356
|
+
- [ ] Focus indicators clearly visible
|
|
357
|
+
- [ ] Logical tab order
|
|
358
|
+
- [ ] Enter/Space activates buttons and links
|
|
359
|
+
- [ ] Escape closes modals and dialogs
|
|
360
|
+
- [ ] No keyboard traps
|
|
361
|
+
|
|
362
|
+
### Screen Reader Tests
|
|
363
|
+
|
|
364
|
+
**Windows (NVDA):**
|
|
365
|
+
- [ ] Install [NVDA](https://www.nvaccess.org/)
|
|
366
|
+
- [ ] Start NVDA
|
|
367
|
+
- [ ] Navigate page with Tab
|
|
368
|
+
- [ ] Verify all content announced
|
|
369
|
+
- [ ] Verify form labels read
|
|
370
|
+
- [ ] Verify button purposes clear
|
|
371
|
+
|
|
372
|
+
**Mac (VoiceOver):**
|
|
373
|
+
- [ ] Press Cmd+F5 to start VoiceOver
|
|
374
|
+
- [ ] Press Ctrl+Option+Arrow to navigate
|
|
375
|
+
- [ ] Verify all content announced
|
|
376
|
+
- [ ] Verify form labels read
|
|
377
|
+
- [ ] Verify button purposes clear
|
|
378
|
+
|
|
379
|
+
### Visual Tests
|
|
380
|
+
|
|
381
|
+
- [ ] Zoom to 200% - content reflows properly
|
|
382
|
+
- [ ] Resize to 320px width - no horizontal scroll
|
|
383
|
+
- [ ] Test with color blindness simulator
|
|
384
|
+
- [ ] Verify focus indicators visible
|
|
385
|
+
- [ ] Check contrast with DevTools
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Browser DevTools
|
|
390
|
+
|
|
391
|
+
### Chrome/Edge Accessibility Panel
|
|
392
|
+
|
|
393
|
+
1. Open DevTools (F12)
|
|
394
|
+
2. Go to "Lighthouse" tab
|
|
395
|
+
3. Select "Accessibility"
|
|
396
|
+
4. Click "Generate report"
|
|
397
|
+
|
|
398
|
+
**Or use Accessibility tree:**
|
|
399
|
+
1. DevTools → Elements tab
|
|
400
|
+
2. Click "Accessibility" in right sidebar
|
|
401
|
+
3. Inspect element accessibility properties
|
|
402
|
+
|
|
403
|
+
### Firefox Accessibility Inspector
|
|
404
|
+
|
|
405
|
+
1. Open DevTools (F12)
|
|
406
|
+
2. Go to "Accessibility" tab
|
|
407
|
+
3. Enable inspector
|
|
408
|
+
4. Click elements to see accessibility info
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Resources
|
|
413
|
+
|
|
414
|
+
### WCAG Guidelines
|
|
415
|
+
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)
|
|
416
|
+
- [Understanding WCAG 2.1](https://www.w3.org/WAI/WCAG21/Understanding/)
|
|
417
|
+
- [WCAG Techniques](https://www.w3.org/WAI/WCAG21/Techniques/)
|
|
418
|
+
|
|
419
|
+
### Testing Tools
|
|
420
|
+
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
|
421
|
+
- [WAVE Browser Extension](https://wave.webaim.org/extension/)
|
|
422
|
+
- [axe DevTools](https://www.deque.com/axe/devtools/)
|
|
423
|
+
- [Accessibility Insights](https://accessibilityinsights.io/)
|
|
424
|
+
- [Lighthouse](https://developers.google.com/web/tools/lighthouse)
|
|
425
|
+
|
|
426
|
+
### Learning Resources
|
|
427
|
+
- [Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/)
|
|
428
|
+
- [A11y Project](https://www.a11yproject.com/)
|
|
429
|
+
- [WebAIM](https://webaim.org/)
|
|
430
|
+
- [Inclusive Components](https://inclusive-components.design/)
|
|
431
|
+
|
|
432
|
+
### Screen Readers
|
|
433
|
+
- [NVDA (Windows)](https://www.nvaccess.org/)
|
|
434
|
+
- [VoiceOver (Mac)](https://www.apple.com/accessibility/voiceover/)
|
|
435
|
+
- [JAWS (Windows)](https://www.freedomscientific.com/products/software/jaws/)
|
|
436
|
+
|
|
437
|
+
### Tailwind Accessibility
|
|
438
|
+
- [Tailwind Focus Ring](https://tailwindcss.com/docs/ring-width)
|
|
439
|
+
- [Tailwind Screen Reader](https://tailwindcss.com/docs/screen-readers)
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Component Patterns
|
|
444
|
+
|
|
445
|
+
### Accessible Button
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
<button
|
|
449
|
+
type="button"
|
|
450
|
+
onClick={handleClick}
|
|
451
|
+
aria-label="Close dialog" // If no visible text
|
|
452
|
+
disabled={isLoading}
|
|
453
|
+
className="bg-platform-primary text-white focus:ring-2 focus:ring-platform-primary focus:ring-offset-2 disabled:opacity-50"
|
|
454
|
+
>
|
|
455
|
+
{isLoading ? "Loading..." : "Submit"}
|
|
456
|
+
</button>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Accessible Link
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
<a
|
|
463
|
+
href="/path"
|
|
464
|
+
className="text-platform-primary underline focus:ring-2 focus:ring-platform-primary focus:ring-offset-2"
|
|
465
|
+
>
|
|
466
|
+
Descriptive link text
|
|
467
|
+
</a>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Accessible Form Input
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
<div className="space-y-2">
|
|
474
|
+
<Label htmlFor="email" className="font-medium">
|
|
475
|
+
Email Address
|
|
476
|
+
<span className="text-red-500 ml-1" aria-hidden="true">*</span>
|
|
477
|
+
</Label>
|
|
478
|
+
<Input
|
|
479
|
+
id="email"
|
|
480
|
+
type="email"
|
|
481
|
+
aria-required="true"
|
|
482
|
+
aria-invalid={!!error}
|
|
483
|
+
aria-describedby={error ? "email-error" : undefined}
|
|
484
|
+
className="focus:border-platform-primary focus:ring-platform-primary"
|
|
485
|
+
/>
|
|
486
|
+
{error && (
|
|
487
|
+
<p id="email-error" className="text-sm text-red-500" role="alert">
|
|
488
|
+
{error}
|
|
489
|
+
</p>
|
|
490
|
+
)}
|
|
491
|
+
</div>
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Accessible Modal
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
<div
|
|
498
|
+
role="dialog"
|
|
499
|
+
aria-modal="true"
|
|
500
|
+
aria-labelledby="dialog-title"
|
|
501
|
+
className="fixed inset-0 z-50 flex items-center justify-center"
|
|
502
|
+
>
|
|
503
|
+
<div className="bg-white p-6 rounded-lg shadow-xl">
|
|
504
|
+
<h2 id="dialog-title" className="text-xl font-semibold">
|
|
505
|
+
Dialog Title
|
|
506
|
+
</h2>
|
|
507
|
+
<div className="mt-4">
|
|
508
|
+
{/* Dialog content */}
|
|
509
|
+
</div>
|
|
510
|
+
<div className="mt-6 flex justify-end gap-2">
|
|
511
|
+
<button
|
|
512
|
+
onClick={onClose}
|
|
513
|
+
className="focus:ring-2 focus:ring-platform-primary"
|
|
514
|
+
>
|
|
515
|
+
Cancel
|
|
516
|
+
</button>
|
|
517
|
+
<button
|
|
518
|
+
onClick={onConfirm}
|
|
519
|
+
className="bg-platform-primary text-white focus:ring-2 focus:ring-platform-primary focus:ring-offset-2"
|
|
520
|
+
>
|
|
521
|
+
Confirm
|
|
522
|
+
</button>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Accessible Data Table
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
<table className="w-full">
|
|
532
|
+
<caption className="sr-only">User list with actions</caption>
|
|
533
|
+
<thead>
|
|
534
|
+
<tr>
|
|
535
|
+
<th scope="col" className="text-left">Name</th>
|
|
536
|
+
<th scope="col" className="text-left">Email</th>
|
|
537
|
+
<th scope="col" className="text-left">Role</th>
|
|
538
|
+
<th scope="col" className="text-right">Actions</th>
|
|
539
|
+
</tr>
|
|
540
|
+
</thead>
|
|
541
|
+
<tbody>
|
|
542
|
+
{users.map(user => (
|
|
543
|
+
<tr key={user.id}>
|
|
544
|
+
<th scope="row" className="font-medium">{user.name}</th>
|
|
545
|
+
<td>{user.email}</td>
|
|
546
|
+
<td>{user.role}</td>
|
|
547
|
+
<td className="text-right space-x-2">
|
|
548
|
+
<button
|
|
549
|
+
aria-label={`Edit ${user.name}`}
|
|
550
|
+
className="focus:ring-2 focus:ring-platform-primary"
|
|
551
|
+
>
|
|
552
|
+
Edit
|
|
553
|
+
</button>
|
|
554
|
+
<button
|
|
555
|
+
aria-label={`Delete ${user.name}`}
|
|
556
|
+
className="focus:ring-2 focus:ring-red-500"
|
|
557
|
+
>
|
|
558
|
+
Delete
|
|
559
|
+
</button>
|
|
560
|
+
</td>
|
|
561
|
+
</tr>
|
|
562
|
+
))}
|
|
563
|
+
</tbody>
|
|
564
|
+
</table>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
## Troubleshooting
|
|
570
|
+
|
|
571
|
+
### Issue: Validation script not found
|
|
572
|
+
|
|
573
|
+
**Error:** `Cannot find module 'validate-accessibility.js'`
|
|
574
|
+
|
|
575
|
+
**Solution:**
|
|
576
|
+
```bash
|
|
577
|
+
# Run from prototype directory
|
|
578
|
+
cd prototype
|
|
579
|
+
npm run validate:a11y
|
|
580
|
+
|
|
581
|
+
# Or use absolute path
|
|
582
|
+
node /path/to/.claude/skills/real-prototypes-skill/scripts/validate-accessibility.js .
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
### Issue: ESLint not finding jsx-a11y plugin
|
|
588
|
+
|
|
589
|
+
**Error:** `Failed to load plugin 'jsx-a11y'`
|
|
590
|
+
|
|
591
|
+
**Solution:**
|
|
592
|
+
```bash
|
|
593
|
+
# Install dependencies
|
|
594
|
+
npm install --save-dev eslint-plugin-jsx-a11y
|
|
595
|
+
|
|
596
|
+
# Or run integration script
|
|
597
|
+
../.claude/skills/real-prototypes-skill/scripts/integrate-accessibility.sh
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
### Issue: False positive on contrast
|
|
603
|
+
|
|
604
|
+
**Problem:** Validator reports contrast issue but it looks fine
|
|
605
|
+
|
|
606
|
+
**Solution:**
|
|
607
|
+
- Use WebAIM Contrast Checker to verify manually
|
|
608
|
+
- Check if element uses gradient or image background
|
|
609
|
+
- Ensure validator is checking correct colors
|
|
610
|
+
- Add exception note in accessibility-fixes.md
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
### Issue: Focus indicator not visible
|
|
615
|
+
|
|
616
|
+
**Problem:** Added focus ring but can't see it
|
|
617
|
+
|
|
618
|
+
**Solution:**
|
|
619
|
+
```typescript
|
|
620
|
+
// Ensure ring-offset for contrast
|
|
621
|
+
focus:ring-2 focus:ring-platform-primary focus:ring-offset-2
|
|
622
|
+
|
|
623
|
+
// Or use outline instead
|
|
624
|
+
focus:outline focus:outline-2 focus:outline-platform-primary
|
|
625
|
+
|
|
626
|
+
// Check if element has position:relative
|
|
627
|
+
className="relative ..."
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Quick Command Reference
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
# Validate accessibility
|
|
636
|
+
npm run validate:a11y
|
|
637
|
+
|
|
638
|
+
# Run ESLint
|
|
639
|
+
npm run lint:a11y
|
|
640
|
+
|
|
641
|
+
# Auto-fix ESLint issues
|
|
642
|
+
npx eslint . --ext .ts,.tsx --fix
|
|
643
|
+
|
|
644
|
+
# Run Lighthouse
|
|
645
|
+
npx lighthouse http://localhost:3000 --only-categories=accessibility
|
|
646
|
+
|
|
647
|
+
# Generate report
|
|
648
|
+
node scripts/validate-accessibility.js . --verbose > report.txt
|
|
649
|
+
|
|
650
|
+
# Check specific file
|
|
651
|
+
npx eslint src/components/MyComponent.tsx
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## Support
|
|
657
|
+
|
|
658
|
+
For questions or issues:
|
|
659
|
+
1. Check `references/accessibility-fixes.md` for detailed guidance
|
|
660
|
+
2. Review `references/accessibility-report.json` for specific issues
|
|
661
|
+
3. Consult WCAG 2.1 Quick Reference for guidelines
|
|
662
|
+
4. Test with browser DevTools Accessibility panel
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
**Last Updated:** 2026-01-26
|
|
667
|
+
**WCAG Version:** 2.1 Level AA
|
|
668
|
+
**Maintained by:** Platform Prototyping Skill
|