@champpaba/claude-agent-kit 3.0.2 → 3.2.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.
Files changed (51) hide show
  1. package/.claude/CHANGELOG.md +707 -0
  2. package/.claude/CLAUDE.md +128 -613
  3. package/.claude/agents/_shared/pre-work-checklist.md +108 -7
  4. package/.claude/commands/cdev.md +36 -0
  5. package/.claude/commands/csetup.md +292 -1791
  6. package/.claude/commands/cview.md +364 -364
  7. package/.claude/contexts/design/accessibility.md +611 -611
  8. package/.claude/contexts/design/layout.md +400 -400
  9. package/.claude/contexts/design/responsive.md +551 -551
  10. package/.claude/contexts/design/shadows.md +522 -522
  11. package/.claude/contexts/design/typography.md +465 -465
  12. package/.claude/contexts/domain/README.md +164 -164
  13. package/.claude/contexts/patterns/agent-coordination.md +388 -388
  14. package/.claude/contexts/patterns/development-principles.md +513 -513
  15. package/.claude/contexts/patterns/error-handling.md +478 -478
  16. package/.claude/contexts/patterns/logging.md +424 -424
  17. package/.claude/contexts/patterns/tdd-classification.md +516 -516
  18. package/.claude/contexts/patterns/testing.md +413 -413
  19. package/.claude/lib/README.md +3 -3
  20. package/.claude/lib/detailed-guides/taskmaster-analysis.md +1 -1
  21. package/.claude/lib/task-analyzer.md +144 -0
  22. package/.claude/lib/tdd-workflow.md +2 -1
  23. package/.claude/lib/validation-gates.md +484 -484
  24. package/.claude/settings.local.json +42 -42
  25. package/.claude/templates/PROJECT_STATUS.template.yml +16 -41
  26. package/.claude/templates/context-template.md +45 -45
  27. package/.claude/templates/flags-template.json +42 -42
  28. package/.claude/templates/phases-sections/accessibility-test.md +17 -17
  29. package/.claude/templates/phases-sections/api-design.md +37 -37
  30. package/.claude/templates/phases-sections/backend-tests.md +16 -16
  31. package/.claude/templates/phases-sections/backend.md +37 -37
  32. package/.claude/templates/phases-sections/business-logic-validation.md +16 -16
  33. package/.claude/templates/phases-sections/component-tests.md +17 -17
  34. package/.claude/templates/phases-sections/contract-backend.md +16 -16
  35. package/.claude/templates/phases-sections/contract-frontend.md +16 -16
  36. package/.claude/templates/phases-sections/database.md +35 -35
  37. package/.claude/templates/phases-sections/e2e-tests.md +16 -16
  38. package/.claude/templates/phases-sections/fix-implementation.md +17 -17
  39. package/.claude/templates/phases-sections/frontend-integration.md +18 -18
  40. package/.claude/templates/phases-sections/manual-flow-test.md +15 -15
  41. package/.claude/templates/phases-sections/manual-ux-test.md +16 -16
  42. package/.claude/templates/phases-sections/refactor-implementation.md +17 -17
  43. package/.claude/templates/phases-sections/refactor.md +16 -16
  44. package/.claude/templates/phases-sections/regression-tests.md +15 -15
  45. package/.claude/templates/phases-sections/responsive-test.md +16 -16
  46. package/.claude/templates/phases-sections/script-implementation.md +43 -43
  47. package/.claude/templates/phases-sections/test-coverage.md +16 -16
  48. package/.claude/templates/phases-sections/user-approval.md +14 -14
  49. package/LICENSE +21 -21
  50. package/package.json +1 -1
  51. package/.claude/lib/tdd-classifier.md +0 -345
@@ -1,611 +1,611 @@
1
- # Accessibility (a11y)
2
-
3
- > **Purpose:** Make web applications usable by everyone, including people with disabilities
4
-
5
- ---
6
-
7
- ## WCAG Standards
8
-
9
- **Web Content Accessibility Guidelines (WCAG) 2.1**
10
-
11
- | Level | Compliance | Use Case |
12
- |-------|------------|----------|
13
- | **A** | Minimum | Basic accessibility (legal requirement in many countries) |
14
- | **AA** | Recommended | Standard for most websites (target this) |
15
- | **AAA** | Enhanced | Government, healthcare, education sites |
16
-
17
- **Target:** WCAG 2.1 Level AA (industry standard)
18
-
19
- ---
20
-
21
- ## Four Principles (POUR)
22
-
23
- ### 1. Perceivable
24
- **Users must be able to perceive the information**
25
-
26
- - ✅ Text alternatives for images
27
- - ✅ Captions for videos
28
- - ✅ Color is not the only way to convey meaning
29
- - ✅ Sufficient color contrast (4.5:1 minimum)
30
-
31
- ### 2. Operable
32
- **Users must be able to operate the interface**
33
-
34
- - ✅ Keyboard accessible (all functions work without mouse)
35
- - ✅ No time limits (or adjustable timers)
36
- - ✅ No flashing content (seizure risk)
37
- - ✅ Skip navigation links
38
-
39
- ### 3. Understandable
40
- **Users must be able to understand the content**
41
-
42
- - ✅ Readable text (plain language)
43
- - ✅ Predictable navigation
44
- - ✅ Clear error messages with suggestions
45
- - ✅ Labels for all form fields
46
-
47
- ### 4. Robust
48
- **Content must be robust enough for assistive technologies**
49
-
50
- - ✅ Valid HTML
51
- - ✅ Semantic markup
52
- - ✅ ARIA attributes when needed
53
- - ✅ Works with screen readers
54
-
55
- ---
56
-
57
- ## Color Contrast
58
-
59
- ### WCAG Requirements
60
-
61
- | Text Type | WCAG AA | WCAG AAA |
62
- |-----------|---------|----------|
63
- | Normal text (<18pt) | **4.5:1** | 7:1 |
64
- | Large text (≥18pt or ≥14pt bold) | **3:1** | 4.5:1 |
65
- | UI components (buttons, inputs) | **3:1** | N/A |
66
-
67
- ### Testing Tools
68
-
69
- **Browser Extensions:**
70
- - **WAVE** (WebAIM) - Visual feedback overlay
71
- - **axe DevTools** - Comprehensive accessibility scanner
72
- - **Lighthouse** (Chrome DevTools) - Automated audit
73
-
74
- **Online Tools:**
75
- - **WebAIM Contrast Checker**: https://webaim.org/resources/contrastchecker/
76
- - **Contrast Ratio**: https://contrast-ratio.com/
77
-
78
- ### Examples
79
-
80
- ```css
81
- /* ✅ PASS - 7:1 contrast */
82
- background: white; /* #FFFFFF */
83
- color: black; /* #000000 */
84
-
85
- /* ✅ PASS - 4.6:1 contrast */
86
- background: #0F2A4A; /* Navy blue */
87
- color: white; /* #FFFFFF */
88
-
89
- /* ❌ FAIL - 2.1:1 contrast */
90
- background: #E0E0E0; /* Light gray */
91
- color: white; /* #FFFFFF */
92
-
93
- /* ❌ FAIL - 1.5:1 contrast */
94
- background: white;
95
- color: #E0E0E0; /* Light gray text */
96
- ```
97
-
98
- ---
99
-
100
- ## Semantic HTML
101
-
102
- **Use proper HTML elements for their intended purpose**
103
-
104
- ### DO (Semantic):
105
-
106
- ```html
107
- <!-- ✅ Navigation -->
108
- <nav>
109
- <ul>
110
- <li><a href="/">Home</a></li>
111
- <li><a href="/about">About</a></li>
112
- </ul>
113
- </nav>
114
-
115
- <!-- ✅ Main content -->
116
- <main>
117
- <article>
118
- <h1>Article Title</h1>
119
- <p>Content...</p>
120
- </article>
121
- </main>
122
-
123
- <!-- ✅ Form -->
124
- <form>
125
- <label for="email">Email:</label>
126
- <input type="email" id="email" name="email" required>
127
- <button type="submit">Submit</button>
128
- </form>
129
-
130
- <!-- ✅ Button -->
131
- <button onclick="doSomething()">Click Me</button>
132
- ```
133
-
134
- ### DON'T (Non-semantic):
135
-
136
- ```html
137
- <!-- ❌ Div soup -->
138
- <div class="nav">
139
- <div class="nav-item">
140
- <span onclick="navigate('/')">Home</span>
141
- </div>
142
- </div>
143
-
144
- <!-- ❌ Divs for everything -->
145
- <div class="main">
146
- <div class="article">
147
- <div class="title">Article Title</div>
148
- <div class="content">Content...</div>
149
- </div>
150
- </div>
151
-
152
- <!-- ❌ Div as button -->
153
- <div onclick="doSomething()">Click Me</div>
154
- ```
155
-
156
- **Why Semantic HTML Matters:**
157
- - ✅ Screen readers understand structure
158
- - ✅ Better SEO
159
- - ✅ Keyboard navigation works automatically
160
- - ✅ Easier to maintain
161
-
162
- ---
163
-
164
- ## Keyboard Navigation
165
-
166
- **All interactive elements must be keyboard accessible**
167
-
168
- ### Tab Order
169
-
170
- **Standard tab order:**
171
- 1. Links
172
- 2. Buttons
173
- 3. Form inputs (text, select, checkbox, radio)
174
- 4. Textareas
175
-
176
- **Control tab order:**
177
- ```html
178
- <!-- Natural tab order (top to bottom) -->
179
- <button>First</button>
180
- <button>Second</button>
181
- <button>Third</button>
182
-
183
- <!-- Custom tab order (avoid if possible) -->
184
- <button tabindex="1">First</button>
185
- <button tabindex="3">Third</button>
186
- <button tabindex="2">Second</button>
187
-
188
- <!-- Remove from tab order -->
189
- <div tabindex="-1">Not focusable</div>
190
-
191
- <!-- Make div focusable (use semantic HTML instead) -->
192
- <div tabindex="0" role="button">Focusable div</div>
193
- ```
194
-
195
- ### Focus Indicators
196
-
197
- **Always visible focus states:**
198
-
199
- ```css
200
- /* ✅ Good focus indicator */
201
- button:focus {
202
- outline: 2px solid var(--color-primary);
203
- outline-offset: 2px;
204
- }
205
-
206
- /* ✅ Alternative (box-shadow) */
207
- input:focus {
208
- outline: none;
209
- box-shadow: 0 0 0 3px rgb(59 130 246 / 0.5);
210
- }
211
-
212
- /* ❌ NEVER remove focus without replacement */
213
- *:focus {
214
- outline: none; /* Makes keyboard navigation impossible */
215
- }
216
- ```
217
-
218
- ### Skip Links
219
-
220
- **Allow keyboard users to skip repetitive navigation:**
221
-
222
- ```html
223
- <!-- Hidden visually but accessible to screen readers -->
224
- <a href="#main-content" class="skip-link">
225
- Skip to main content
226
- </a>
227
-
228
- <nav>
229
- <!-- Navigation items -->
230
- </nav>
231
-
232
- <main id="main-content">
233
- <!-- Main content -->
234
- </main>
235
- ```
236
-
237
- ```css
238
- .skip-link {
239
- position: absolute;
240
- top: -40px;
241
- left: 0;
242
- background: var(--color-primary);
243
- color: white;
244
- padding: var(--spacing-2);
245
- z-index: 1000;
246
- }
247
-
248
- .skip-link:focus {
249
- top: 0; /* Show on focus */
250
- }
251
- ```
252
-
253
- ---
254
-
255
- ## ARIA (Accessible Rich Internet Applications)
256
-
257
- **Use ARIA when semantic HTML is not enough**
258
-
259
- ### ARIA Roles
260
-
261
- ```html
262
- <!-- ✅ Use semantic HTML first -->
263
- <nav>Navigation</nav>
264
- <main>Main content</main>
265
- <aside>Sidebar</aside>
266
-
267
- <!-- ⚠️ Use ARIA when semantic HTML unavailable -->
268
- <div role="navigation">Navigation</div>
269
- <div role="main">Main content</div>
270
- <div role="complementary">Sidebar</div>
271
-
272
- <!-- Common roles -->
273
- <div role="button">Custom button</div>
274
- <div role="alert">Important message</div>
275
- <div role="dialog">Modal dialog</div>
276
- <div role="search">Search form</div>
277
- ```
278
-
279
- ### ARIA Labels
280
-
281
- ```html
282
- <!-- Button with no visible text -->
283
- <button aria-label="Close dialog">
284
- <svg><!-- X icon --></svg>
285
- </button>
286
-
287
- <!-- Icon-only link -->
288
- <a href="/profile" aria-label="Go to profile">
289
- <svg><!-- User icon --></svg>
290
- </a>
291
-
292
- <!-- Describe element -->
293
- <button aria-describedby="help-text">
294
- Submit
295
- </button>
296
- <p id="help-text">
297
- This will send your form data
298
- </p>
299
- ```
300
-
301
- ### ARIA States
302
-
303
- ```html
304
- <!-- Expanded/collapsed -->
305
- <button aria-expanded="false" aria-controls="menu">
306
- Menu
307
- </button>
308
- <div id="menu" hidden>
309
- <!-- Menu items -->
310
- </div>
311
-
312
- <!-- Checked (custom checkbox) -->
313
- <div role="checkbox" aria-checked="true">
314
- I agree to terms
315
- </div>
316
-
317
- <!-- Hidden from screen readers -->
318
- <div aria-hidden="true">
319
- Decorative content
320
- </div>
321
-
322
- <!-- Current page in navigation -->
323
- <nav>
324
- <a href="/" aria-current="page">Home</a>
325
- <a href="/about">About</a>
326
- </nav>
327
- ```
328
-
329
- ### ARIA Live Regions
330
-
331
- **Announce dynamic content changes:**
332
-
333
- ```html
334
- <!-- Polite (wait for user to finish) -->
335
- <div aria-live="polite">
336
- 3 new messages
337
- </div>
338
-
339
- <!-- Assertive (interrupt immediately) -->
340
- <div aria-live="assertive" role="alert">
341
- Error: Form submission failed
342
- </div>
343
-
344
- <!-- Atomic (read entire region) -->
345
- <div aria-live="polite" aria-atomic="true">
346
- Loading: 45% complete
347
- </div>
348
- ```
349
-
350
- ---
351
-
352
- ## Form Accessibility
353
-
354
- ### Labels
355
-
356
- **Always associate labels with inputs:**
357
-
358
- ```html
359
- <!-- ✅ Method 1: for/id -->
360
- <label for="username">Username:</label>
361
- <input type="text" id="username" name="username">
362
-
363
- <!-- ✅ Method 2: Wrapping -->
364
- <label>
365
- Email:
366
- <input type="email" name="email">
367
- </label>
368
-
369
- <!-- ❌ No association -->
370
- <span>Password:</span>
371
- <input type="password" name="password">
372
- ```
373
-
374
- ### Required Fields
375
-
376
- ```html
377
- <!-- ✅ HTML5 required -->
378
- <label for="email">Email (required):</label>
379
- <input type="email" id="email" name="email" required>
380
-
381
- <!-- ✅ ARIA required -->
382
- <label for="phone">Phone:</label>
383
- <input type="tel" id="phone" name="phone" aria-required="true">
384
-
385
- <!-- ✅ Visual indicator + text -->
386
- <label for="name">
387
- Name <span aria-label="required">*</span>
388
- </label>
389
- <input type="text" id="name" name="name" required>
390
- ```
391
-
392
- ### Error Messages
393
-
394
- ```html
395
- <!-- ✅ Associate error with input -->
396
- <label for="email">Email:</label>
397
- <input
398
- type="email"
399
- id="email"
400
- name="email"
401
- aria-invalid="true"
402
- aria-describedby="email-error"
403
- >
404
- <p id="email-error" role="alert">
405
- Please enter a valid email address
406
- </p>
407
- ```
408
-
409
- ### Fieldsets
410
-
411
- **Group related inputs:**
412
-
413
- ```html
414
- <fieldset>
415
- <legend>Shipping Address</legend>
416
-
417
- <label for="street">Street:</label>
418
- <input type="text" id="street" name="street">
419
-
420
- <label for="city">City:</label>
421
- <input type="text" id="city" name="city">
422
- </fieldset>
423
- ```
424
-
425
- ---
426
-
427
- ## Image Accessibility
428
-
429
- ### Alt Text
430
-
431
- ```html
432
- <!-- ✅ Descriptive alt text -->
433
- <img
434
- src="sunset.jpg"
435
- alt="Orange sunset over ocean with waves crashing on rocks"
436
- >
437
-
438
- <!-- ✅ Decorative image (empty alt) -->
439
- <img src="decorative-line.svg" alt="">
440
-
441
- <!-- ✅ Functional image (describe function) -->
442
- <button>
443
- <img src="trash.svg" alt="Delete item">
444
- </button>
445
-
446
- <!-- ❌ Missing alt -->
447
- <img src="important.jpg">
448
-
449
- <!-- ❌ Redundant alt -->
450
- <img src="photo-sunset.jpg" alt="Image of sunset">
451
- ```
452
-
453
- ### Complex Images
454
-
455
- ```html
456
- <!-- Chart or infographic -->
457
- <figure>
458
- <img
459
- src="sales-chart.png"
460
- alt="Bar chart showing quarterly sales"
461
- aria-describedby="chart-desc"
462
- >
463
- <figcaption id="chart-desc">
464
- Q1: $10k, Q2: $15k, Q3: $12k, Q4: $18k
465
- </figcaption>
466
- </figure>
467
- ```
468
-
469
- ---
470
-
471
- ## Modal Dialogs
472
-
473
- **Accessible modal implementation:**
474
-
475
- ```html
476
- <div
477
- role="dialog"
478
- aria-labelledby="dialog-title"
479
- aria-modal="true"
480
- >
481
- <h2 id="dialog-title">Confirm Action</h2>
482
- <p>Are you sure you want to delete this item?</p>
483
-
484
- <button>Cancel</button>
485
- <button>Delete</button>
486
- </div>
487
- ```
488
-
489
- ```javascript
490
- // Focus management
491
- function openModal(modalId) {
492
- const modal = document.getElementById(modalId);
493
- const focusableElements = modal.querySelectorAll(
494
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
495
- );
496
-
497
- // Store last focused element
498
- const lastFocused = document.activeElement;
499
-
500
- // Show modal
501
- modal.removeAttribute('hidden');
502
-
503
- // Focus first element
504
- focusableElements[0].focus();
505
-
506
- // Trap focus inside modal
507
- modal.addEventListener('keydown', (e) => {
508
- if (e.key === 'Escape') {
509
- closeModal(modalId);
510
- }
511
-
512
- if (e.key === 'Tab') {
513
- // Trap focus (cycle through focusable elements)
514
- }
515
- });
516
- }
517
-
518
- function closeModal(modalId) {
519
- const modal = document.getElementById(modalId);
520
- modal.setAttribute('hidden', '');
521
-
522
- // Return focus to trigger element
523
- lastFocused.focus();
524
- }
525
- ```
526
-
527
- ---
528
-
529
- ## Best Practices
530
-
531
- ### DO:
532
- - ✅ Use semantic HTML elements
533
- - ✅ Ensure 4.5:1 contrast for text
534
- - ✅ Provide text alternatives for images
535
- - ✅ Make all functionality keyboard accessible
536
- - ✅ Use visible focus indicators
537
- - ✅ Associate labels with form inputs
538
- - ✅ Test with screen readers (NVDA, JAWS, VoiceOver)
539
- - ✅ Add ARIA attributes when semantic HTML insufficient
540
-
541
- ### DON'T:
542
- - ❌ Use color alone to convey meaning
543
- - ❌ Remove focus indicators without replacement
544
- - ❌ Use divs/spans for interactive elements
545
- - ❌ Forget alt text on images
546
- - ❌ Auto-play videos with sound
547
- - ❌ Use ARIA when semantic HTML exists
548
- - ❌ Forget to test with keyboard only
549
- - ❌ Rely only on automated testing (manual testing crucial)
550
-
551
- ---
552
-
553
- ## Testing Checklist
554
-
555
- ### Automated Testing
556
-
557
- - [ ] Run Lighthouse audit (Chrome DevTools)
558
- - [ ] Run axe DevTools extension
559
- - [ ] Run WAVE extension
560
- - [ ] Check HTML validation (W3C Validator)
561
-
562
- ### Manual Testing
563
-
564
- - [ ] Navigate entire site with keyboard only (no mouse)
565
- - [ ] Test with screen reader (NVDA/JAWS/VoiceOver)
566
- - [ ] Zoom to 200% (content should reflow, not scroll horizontally)
567
- - [ ] Test color contrast (all text/UI components)
568
- - [ ] Disable images (alt text should convey meaning)
569
- - [ ] Test forms (labels, errors, validation)
570
-
571
- ### Device Testing
572
-
573
- - [ ] Desktop browsers (Chrome, Firefox, Safari, Edge)
574
- - [ ] Mobile browsers (iOS Safari, Chrome Mobile)
575
- - [ ] Screen readers (NVDA on Windows, VoiceOver on macOS/iOS)
576
- - [ ] Keyboard-only navigation
577
- - [ ] Touch screen navigation
578
-
579
- ---
580
-
581
- ## Quick Reference
582
-
583
- **Contrast Ratios:**
584
- | Element | Minimum Ratio |
585
- |---------|---------------|
586
- | Normal text | 4.5:1 (AA) |
587
- | Large text | 3:1 (AA) |
588
- | UI components | 3:1 (AA) |
589
-
590
- **Keyboard Shortcuts:**
591
- | Key | Action |
592
- |-----|--------|
593
- | Tab | Move to next focusable element |
594
- | Shift + Tab | Move to previous element |
595
- | Enter | Activate button/link |
596
- | Space | Toggle checkbox, activate button |
597
- | Esc | Close modal/dialog |
598
- | Arrow keys | Navigate within component |
599
-
600
- **ARIA Landmarks:**
601
- | Role | Semantic HTML |
602
- |------|---------------|
603
- | `role="navigation"` | `<nav>` |
604
- | `role="main"` | `<main>` |
605
- | `role="complementary"` | `<aside>` |
606
- | `role="contentinfo"` | `<footer>` |
607
- | `role="banner"` | `<header>` |
608
-
609
- ---
610
-
611
- **💡 Remember:** Accessibility benefits everyone, not just people with disabilities!
1
+ # Accessibility (a11y)
2
+
3
+ > **Purpose:** Make web applications usable by everyone, including people with disabilities
4
+
5
+ ---
6
+
7
+ ## WCAG Standards
8
+
9
+ **Web Content Accessibility Guidelines (WCAG) 2.1**
10
+
11
+ | Level | Compliance | Use Case |
12
+ |-------|------------|----------|
13
+ | **A** | Minimum | Basic accessibility (legal requirement in many countries) |
14
+ | **AA** | Recommended | Standard for most websites (target this) |
15
+ | **AAA** | Enhanced | Government, healthcare, education sites |
16
+
17
+ **Target:** WCAG 2.1 Level AA (industry standard)
18
+
19
+ ---
20
+
21
+ ## Four Principles (POUR)
22
+
23
+ ### 1. Perceivable
24
+ **Users must be able to perceive the information**
25
+
26
+ - ✅ Text alternatives for images
27
+ - ✅ Captions for videos
28
+ - ✅ Color is not the only way to convey meaning
29
+ - ✅ Sufficient color contrast (4.5:1 minimum)
30
+
31
+ ### 2. Operable
32
+ **Users must be able to operate the interface**
33
+
34
+ - ✅ Keyboard accessible (all functions work without mouse)
35
+ - ✅ No time limits (or adjustable timers)
36
+ - ✅ No flashing content (seizure risk)
37
+ - ✅ Skip navigation links
38
+
39
+ ### 3. Understandable
40
+ **Users must be able to understand the content**
41
+
42
+ - ✅ Readable text (plain language)
43
+ - ✅ Predictable navigation
44
+ - ✅ Clear error messages with suggestions
45
+ - ✅ Labels for all form fields
46
+
47
+ ### 4. Robust
48
+ **Content must be robust enough for assistive technologies**
49
+
50
+ - ✅ Valid HTML
51
+ - ✅ Semantic markup
52
+ - ✅ ARIA attributes when needed
53
+ - ✅ Works with screen readers
54
+
55
+ ---
56
+
57
+ ## Color Contrast
58
+
59
+ ### WCAG Requirements
60
+
61
+ | Text Type | WCAG AA | WCAG AAA |
62
+ |-----------|---------|----------|
63
+ | Normal text (<18pt) | **4.5:1** | 7:1 |
64
+ | Large text (≥18pt or ≥14pt bold) | **3:1** | 4.5:1 |
65
+ | UI components (buttons, inputs) | **3:1** | N/A |
66
+
67
+ ### Testing Tools
68
+
69
+ **Browser Extensions:**
70
+ - **WAVE** (WebAIM) - Visual feedback overlay
71
+ - **axe DevTools** - Comprehensive accessibility scanner
72
+ - **Lighthouse** (Chrome DevTools) - Automated audit
73
+
74
+ **Online Tools:**
75
+ - **WebAIM Contrast Checker**: https://webaim.org/resources/contrastchecker/
76
+ - **Contrast Ratio**: https://contrast-ratio.com/
77
+
78
+ ### Examples
79
+
80
+ ```css
81
+ /* ✅ PASS - 7:1 contrast */
82
+ background: white; /* #FFFFFF */
83
+ color: black; /* #000000 */
84
+
85
+ /* ✅ PASS - 4.6:1 contrast */
86
+ background: #0F2A4A; /* Navy blue */
87
+ color: white; /* #FFFFFF */
88
+
89
+ /* ❌ FAIL - 2.1:1 contrast */
90
+ background: #E0E0E0; /* Light gray */
91
+ color: white; /* #FFFFFF */
92
+
93
+ /* ❌ FAIL - 1.5:1 contrast */
94
+ background: white;
95
+ color: #E0E0E0; /* Light gray text */
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Semantic HTML
101
+
102
+ **Use proper HTML elements for their intended purpose**
103
+
104
+ ### DO (Semantic):
105
+
106
+ ```html
107
+ <!-- ✅ Navigation -->
108
+ <nav>
109
+ <ul>
110
+ <li><a href="/">Home</a></li>
111
+ <li><a href="/about">About</a></li>
112
+ </ul>
113
+ </nav>
114
+
115
+ <!-- ✅ Main content -->
116
+ <main>
117
+ <article>
118
+ <h1>Article Title</h1>
119
+ <p>Content...</p>
120
+ </article>
121
+ </main>
122
+
123
+ <!-- ✅ Form -->
124
+ <form>
125
+ <label for="email">Email:</label>
126
+ <input type="email" id="email" name="email" required>
127
+ <button type="submit">Submit</button>
128
+ </form>
129
+
130
+ <!-- ✅ Button -->
131
+ <button onclick="doSomething()">Click Me</button>
132
+ ```
133
+
134
+ ### DON'T (Non-semantic):
135
+
136
+ ```html
137
+ <!-- ❌ Div soup -->
138
+ <div class="nav">
139
+ <div class="nav-item">
140
+ <span onclick="navigate('/')">Home</span>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- ❌ Divs for everything -->
145
+ <div class="main">
146
+ <div class="article">
147
+ <div class="title">Article Title</div>
148
+ <div class="content">Content...</div>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- ❌ Div as button -->
153
+ <div onclick="doSomething()">Click Me</div>
154
+ ```
155
+
156
+ **Why Semantic HTML Matters:**
157
+ - ✅ Screen readers understand structure
158
+ - ✅ Better SEO
159
+ - ✅ Keyboard navigation works automatically
160
+ - ✅ Easier to maintain
161
+
162
+ ---
163
+
164
+ ## Keyboard Navigation
165
+
166
+ **All interactive elements must be keyboard accessible**
167
+
168
+ ### Tab Order
169
+
170
+ **Standard tab order:**
171
+ 1. Links
172
+ 2. Buttons
173
+ 3. Form inputs (text, select, checkbox, radio)
174
+ 4. Textareas
175
+
176
+ **Control tab order:**
177
+ ```html
178
+ <!-- Natural tab order (top to bottom) -->
179
+ <button>First</button>
180
+ <button>Second</button>
181
+ <button>Third</button>
182
+
183
+ <!-- Custom tab order (avoid if possible) -->
184
+ <button tabindex="1">First</button>
185
+ <button tabindex="3">Third</button>
186
+ <button tabindex="2">Second</button>
187
+
188
+ <!-- Remove from tab order -->
189
+ <div tabindex="-1">Not focusable</div>
190
+
191
+ <!-- Make div focusable (use semantic HTML instead) -->
192
+ <div tabindex="0" role="button">Focusable div</div>
193
+ ```
194
+
195
+ ### Focus Indicators
196
+
197
+ **Always visible focus states:**
198
+
199
+ ```css
200
+ /* ✅ Good focus indicator */
201
+ button:focus {
202
+ outline: 2px solid var(--color-primary);
203
+ outline-offset: 2px;
204
+ }
205
+
206
+ /* ✅ Alternative (box-shadow) */
207
+ input:focus {
208
+ outline: none;
209
+ box-shadow: 0 0 0 3px rgb(59 130 246 / 0.5);
210
+ }
211
+
212
+ /* ❌ NEVER remove focus without replacement */
213
+ *:focus {
214
+ outline: none; /* Makes keyboard navigation impossible */
215
+ }
216
+ ```
217
+
218
+ ### Skip Links
219
+
220
+ **Allow keyboard users to skip repetitive navigation:**
221
+
222
+ ```html
223
+ <!-- Hidden visually but accessible to screen readers -->
224
+ <a href="#main-content" class="skip-link">
225
+ Skip to main content
226
+ </a>
227
+
228
+ <nav>
229
+ <!-- Navigation items -->
230
+ </nav>
231
+
232
+ <main id="main-content">
233
+ <!-- Main content -->
234
+ </main>
235
+ ```
236
+
237
+ ```css
238
+ .skip-link {
239
+ position: absolute;
240
+ top: -40px;
241
+ left: 0;
242
+ background: var(--color-primary);
243
+ color: white;
244
+ padding: var(--spacing-2);
245
+ z-index: 1000;
246
+ }
247
+
248
+ .skip-link:focus {
249
+ top: 0; /* Show on focus */
250
+ }
251
+ ```
252
+
253
+ ---
254
+
255
+ ## ARIA (Accessible Rich Internet Applications)
256
+
257
+ **Use ARIA when semantic HTML is not enough**
258
+
259
+ ### ARIA Roles
260
+
261
+ ```html
262
+ <!-- ✅ Use semantic HTML first -->
263
+ <nav>Navigation</nav>
264
+ <main>Main content</main>
265
+ <aside>Sidebar</aside>
266
+
267
+ <!-- ⚠️ Use ARIA when semantic HTML unavailable -->
268
+ <div role="navigation">Navigation</div>
269
+ <div role="main">Main content</div>
270
+ <div role="complementary">Sidebar</div>
271
+
272
+ <!-- Common roles -->
273
+ <div role="button">Custom button</div>
274
+ <div role="alert">Important message</div>
275
+ <div role="dialog">Modal dialog</div>
276
+ <div role="search">Search form</div>
277
+ ```
278
+
279
+ ### ARIA Labels
280
+
281
+ ```html
282
+ <!-- Button with no visible text -->
283
+ <button aria-label="Close dialog">
284
+ <svg><!-- X icon --></svg>
285
+ </button>
286
+
287
+ <!-- Icon-only link -->
288
+ <a href="/profile" aria-label="Go to profile">
289
+ <svg><!-- User icon --></svg>
290
+ </a>
291
+
292
+ <!-- Describe element -->
293
+ <button aria-describedby="help-text">
294
+ Submit
295
+ </button>
296
+ <p id="help-text">
297
+ This will send your form data
298
+ </p>
299
+ ```
300
+
301
+ ### ARIA States
302
+
303
+ ```html
304
+ <!-- Expanded/collapsed -->
305
+ <button aria-expanded="false" aria-controls="menu">
306
+ Menu
307
+ </button>
308
+ <div id="menu" hidden>
309
+ <!-- Menu items -->
310
+ </div>
311
+
312
+ <!-- Checked (custom checkbox) -->
313
+ <div role="checkbox" aria-checked="true">
314
+ I agree to terms
315
+ </div>
316
+
317
+ <!-- Hidden from screen readers -->
318
+ <div aria-hidden="true">
319
+ Decorative content
320
+ </div>
321
+
322
+ <!-- Current page in navigation -->
323
+ <nav>
324
+ <a href="/" aria-current="page">Home</a>
325
+ <a href="/about">About</a>
326
+ </nav>
327
+ ```
328
+
329
+ ### ARIA Live Regions
330
+
331
+ **Announce dynamic content changes:**
332
+
333
+ ```html
334
+ <!-- Polite (wait for user to finish) -->
335
+ <div aria-live="polite">
336
+ 3 new messages
337
+ </div>
338
+
339
+ <!-- Assertive (interrupt immediately) -->
340
+ <div aria-live="assertive" role="alert">
341
+ Error: Form submission failed
342
+ </div>
343
+
344
+ <!-- Atomic (read entire region) -->
345
+ <div aria-live="polite" aria-atomic="true">
346
+ Loading: 45% complete
347
+ </div>
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Form Accessibility
353
+
354
+ ### Labels
355
+
356
+ **Always associate labels with inputs:**
357
+
358
+ ```html
359
+ <!-- ✅ Method 1: for/id -->
360
+ <label for="username">Username:</label>
361
+ <input type="text" id="username" name="username">
362
+
363
+ <!-- ✅ Method 2: Wrapping -->
364
+ <label>
365
+ Email:
366
+ <input type="email" name="email">
367
+ </label>
368
+
369
+ <!-- ❌ No association -->
370
+ <span>Password:</span>
371
+ <input type="password" name="password">
372
+ ```
373
+
374
+ ### Required Fields
375
+
376
+ ```html
377
+ <!-- ✅ HTML5 required -->
378
+ <label for="email">Email (required):</label>
379
+ <input type="email" id="email" name="email" required>
380
+
381
+ <!-- ✅ ARIA required -->
382
+ <label for="phone">Phone:</label>
383
+ <input type="tel" id="phone" name="phone" aria-required="true">
384
+
385
+ <!-- ✅ Visual indicator + text -->
386
+ <label for="name">
387
+ Name <span aria-label="required">*</span>
388
+ </label>
389
+ <input type="text" id="name" name="name" required>
390
+ ```
391
+
392
+ ### Error Messages
393
+
394
+ ```html
395
+ <!-- ✅ Associate error with input -->
396
+ <label for="email">Email:</label>
397
+ <input
398
+ type="email"
399
+ id="email"
400
+ name="email"
401
+ aria-invalid="true"
402
+ aria-describedby="email-error"
403
+ >
404
+ <p id="email-error" role="alert">
405
+ Please enter a valid email address
406
+ </p>
407
+ ```
408
+
409
+ ### Fieldsets
410
+
411
+ **Group related inputs:**
412
+
413
+ ```html
414
+ <fieldset>
415
+ <legend>Shipping Address</legend>
416
+
417
+ <label for="street">Street:</label>
418
+ <input type="text" id="street" name="street">
419
+
420
+ <label for="city">City:</label>
421
+ <input type="text" id="city" name="city">
422
+ </fieldset>
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Image Accessibility
428
+
429
+ ### Alt Text
430
+
431
+ ```html
432
+ <!-- ✅ Descriptive alt text -->
433
+ <img
434
+ src="sunset.jpg"
435
+ alt="Orange sunset over ocean with waves crashing on rocks"
436
+ >
437
+
438
+ <!-- ✅ Decorative image (empty alt) -->
439
+ <img src="decorative-line.svg" alt="">
440
+
441
+ <!-- ✅ Functional image (describe function) -->
442
+ <button>
443
+ <img src="trash.svg" alt="Delete item">
444
+ </button>
445
+
446
+ <!-- ❌ Missing alt -->
447
+ <img src="important.jpg">
448
+
449
+ <!-- ❌ Redundant alt -->
450
+ <img src="photo-sunset.jpg" alt="Image of sunset">
451
+ ```
452
+
453
+ ### Complex Images
454
+
455
+ ```html
456
+ <!-- Chart or infographic -->
457
+ <figure>
458
+ <img
459
+ src="sales-chart.png"
460
+ alt="Bar chart showing quarterly sales"
461
+ aria-describedby="chart-desc"
462
+ >
463
+ <figcaption id="chart-desc">
464
+ Q1: $10k, Q2: $15k, Q3: $12k, Q4: $18k
465
+ </figcaption>
466
+ </figure>
467
+ ```
468
+
469
+ ---
470
+
471
+ ## Modal Dialogs
472
+
473
+ **Accessible modal implementation:**
474
+
475
+ ```html
476
+ <div
477
+ role="dialog"
478
+ aria-labelledby="dialog-title"
479
+ aria-modal="true"
480
+ >
481
+ <h2 id="dialog-title">Confirm Action</h2>
482
+ <p>Are you sure you want to delete this item?</p>
483
+
484
+ <button>Cancel</button>
485
+ <button>Delete</button>
486
+ </div>
487
+ ```
488
+
489
+ ```javascript
490
+ // Focus management
491
+ function openModal(modalId) {
492
+ const modal = document.getElementById(modalId);
493
+ const focusableElements = modal.querySelectorAll(
494
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
495
+ );
496
+
497
+ // Store last focused element
498
+ const lastFocused = document.activeElement;
499
+
500
+ // Show modal
501
+ modal.removeAttribute('hidden');
502
+
503
+ // Focus first element
504
+ focusableElements[0].focus();
505
+
506
+ // Trap focus inside modal
507
+ modal.addEventListener('keydown', (e) => {
508
+ if (e.key === 'Escape') {
509
+ closeModal(modalId);
510
+ }
511
+
512
+ if (e.key === 'Tab') {
513
+ // Trap focus (cycle through focusable elements)
514
+ }
515
+ });
516
+ }
517
+
518
+ function closeModal(modalId) {
519
+ const modal = document.getElementById(modalId);
520
+ modal.setAttribute('hidden', '');
521
+
522
+ // Return focus to trigger element
523
+ lastFocused.focus();
524
+ }
525
+ ```
526
+
527
+ ---
528
+
529
+ ## Best Practices
530
+
531
+ ### DO:
532
+ - ✅ Use semantic HTML elements
533
+ - ✅ Ensure 4.5:1 contrast for text
534
+ - ✅ Provide text alternatives for images
535
+ - ✅ Make all functionality keyboard accessible
536
+ - ✅ Use visible focus indicators
537
+ - ✅ Associate labels with form inputs
538
+ - ✅ Test with screen readers (NVDA, JAWS, VoiceOver)
539
+ - ✅ Add ARIA attributes when semantic HTML insufficient
540
+
541
+ ### DON'T:
542
+ - ❌ Use color alone to convey meaning
543
+ - ❌ Remove focus indicators without replacement
544
+ - ❌ Use divs/spans for interactive elements
545
+ - ❌ Forget alt text on images
546
+ - ❌ Auto-play videos with sound
547
+ - ❌ Use ARIA when semantic HTML exists
548
+ - ❌ Forget to test with keyboard only
549
+ - ❌ Rely only on automated testing (manual testing crucial)
550
+
551
+ ---
552
+
553
+ ## Testing Checklist
554
+
555
+ ### Automated Testing
556
+
557
+ - [ ] Run Lighthouse audit (Chrome DevTools)
558
+ - [ ] Run axe DevTools extension
559
+ - [ ] Run WAVE extension
560
+ - [ ] Check HTML validation (W3C Validator)
561
+
562
+ ### Manual Testing
563
+
564
+ - [ ] Navigate entire site with keyboard only (no mouse)
565
+ - [ ] Test with screen reader (NVDA/JAWS/VoiceOver)
566
+ - [ ] Zoom to 200% (content should reflow, not scroll horizontally)
567
+ - [ ] Test color contrast (all text/UI components)
568
+ - [ ] Disable images (alt text should convey meaning)
569
+ - [ ] Test forms (labels, errors, validation)
570
+
571
+ ### Device Testing
572
+
573
+ - [ ] Desktop browsers (Chrome, Firefox, Safari, Edge)
574
+ - [ ] Mobile browsers (iOS Safari, Chrome Mobile)
575
+ - [ ] Screen readers (NVDA on Windows, VoiceOver on macOS/iOS)
576
+ - [ ] Keyboard-only navigation
577
+ - [ ] Touch screen navigation
578
+
579
+ ---
580
+
581
+ ## Quick Reference
582
+
583
+ **Contrast Ratios:**
584
+ | Element | Minimum Ratio |
585
+ |---------|---------------|
586
+ | Normal text | 4.5:1 (AA) |
587
+ | Large text | 3:1 (AA) |
588
+ | UI components | 3:1 (AA) |
589
+
590
+ **Keyboard Shortcuts:**
591
+ | Key | Action |
592
+ |-----|--------|
593
+ | Tab | Move to next focusable element |
594
+ | Shift + Tab | Move to previous element |
595
+ | Enter | Activate button/link |
596
+ | Space | Toggle checkbox, activate button |
597
+ | Esc | Close modal/dialog |
598
+ | Arrow keys | Navigate within component |
599
+
600
+ **ARIA Landmarks:**
601
+ | Role | Semantic HTML |
602
+ |------|---------------|
603
+ | `role="navigation"` | `<nav>` |
604
+ | `role="main"` | `<main>` |
605
+ | `role="complementary"` | `<aside>` |
606
+ | `role="contentinfo"` | `<footer>` |
607
+ | `role="banner"` | `<header>` |
608
+
609
+ ---
610
+
611
+ **💡 Remember:** Accessibility benefits everyone, not just people with disabilities!