Initial commit
This commit is contained in:
16
skills/analysis/accessibility-audit/CHANGELOG.md
Normal file
16
skills/analysis/accessibility-audit/CHANGELOG.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the accessibility-audit skill will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.0] - 2025-11-27
|
||||
|
||||
### Added
|
||||
- Initial Claudex marketplace release
|
||||
- Risk-based severity scoring (Impact x Likelihood model)
|
||||
- MUI framework awareness to prevent false positives
|
||||
- Multi-layer analysis workflow (static, runtime, manual)
|
||||
- Comprehensive WCAG 2.2 Level AA criteria reference
|
||||
- Gap report and remediation plan examples
|
||||
51
skills/analysis/accessibility-audit/README.md
Normal file
51
skills/analysis/accessibility-audit/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Accessibility Audit
|
||||
|
||||
WCAG 2.2 Level AA accessibility auditing with risk-based severity scoring for React/TypeScript applications.
|
||||
|
||||
## Overview
|
||||
|
||||
This skill provides comprehensive accessibility auditing that goes beyond simple WCAG conformance checking. It uses a **risk-based severity model** where Severity = Impact x Likelihood, meaning a Level A failure can be LOW severity while a Level AA failure can be CRITICAL.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Risk-based severity scoring** - Prioritizes issues by real user impact
|
||||
- **MUI framework awareness** - Avoids false positives on built-in accessibility features
|
||||
- **Multi-layer analysis** - Static (ESLint), runtime (jest-axe, Playwright), and manual validation
|
||||
- **Actionable output** - Gap reports with remediation priorities
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Install required tooling
|
||||
npm install --save-dev eslint-plugin-jsx-a11y jest-axe @axe-core/playwright
|
||||
|
||||
# Run audit
|
||||
# Use trigger: "Run accessibility audit on [component/page]"
|
||||
```
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "accessibility audit"
|
||||
- "WCAG compliance"
|
||||
- "a11y review"
|
||||
- "screen reader"
|
||||
- "keyboard navigation"
|
||||
- "color contrast"
|
||||
|
||||
## Severity Levels
|
||||
|
||||
| Severity | Impact | Examples |
|
||||
|----------|--------|----------|
|
||||
| Critical | Blocks access | Keyboard traps, missing alt on actions |
|
||||
| High | Significantly degrades UX | Poor contrast on CTAs, no skip navigation |
|
||||
| Medium | Minor usability impact | Missing autocomplete, unclear link text |
|
||||
| Low | Best practice | Could add tooltips, more descriptive titles |
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `codebase-auditor` - General code quality analysis
|
||||
- `bulletproof-react-auditor` - React architecture review
|
||||
|
||||
## Documentation
|
||||
|
||||
See [SKILL.md](SKILL.md) for the complete workflow and reference materials.
|
||||
85
skills/analysis/accessibility-audit/SKILL.md
Normal file
85
skills/analysis/accessibility-audit/SKILL.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: accessibility-audit
|
||||
version: 0.1.0
|
||||
description: WCAG 2.2 Level AA accessibility auditing with risk-based severity scoring
|
||||
author: Connor
|
||||
triggers:
|
||||
- accessibility audit
|
||||
- WCAG compliance
|
||||
- a11y review
|
||||
- screen reader
|
||||
- keyboard navigation
|
||||
- color contrast
|
||||
---
|
||||
|
||||
# Accessibility Audit Skill
|
||||
|
||||
Comprehensive WCAG 2.2 Level AA accessibility auditing for React/TypeScript applications with MUI framework awareness.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Severity | Impact | Examples |
|
||||
|----------|--------|----------|
|
||||
| **Critical** | Blocks access completely | Keyboard traps, missing alt on actions, no focus visible |
|
||||
| **High** | Significantly degrades UX | Poor contrast on CTAs, no skip navigation, small touch targets |
|
||||
| **Medium** | Minor usability impact | Missing autocomplete, unclear link text |
|
||||
| **Low** | Best practice enhancement | Could add tooltips, more descriptive titles |
|
||||
|
||||
## Key Principle
|
||||
|
||||
> **Severity = Impact x Likelihood**, NOT WCAG conformance level.
|
||||
> A Level A failure can be LOW severity; a Level AA failure can be CRITICAL.
|
||||
|
||||
## Required Tooling
|
||||
|
||||
```bash
|
||||
# Install required tools
|
||||
npm install --save-dev eslint-plugin-jsx-a11y jest-axe @axe-core/playwright
|
||||
|
||||
# Configure ESLint
|
||||
# Add to .eslintrc: extends: ['plugin:jsx-a11y/recommended']
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
| Phase | Description |
|
||||
|-------|-------------|
|
||||
| 1. Setup | Install tooling, create output directories |
|
||||
| 2. Static Analysis | ESLint jsx-a11y scan |
|
||||
| 3. Runtime Analysis | jest-axe and Playwright |
|
||||
| 4. Manual Validation | Keyboard, screen reader, contrast |
|
||||
| 5. Report Generation | JSON + Markdown outputs |
|
||||
|
||||
### Phase 1: Setup
|
||||
|
||||
See [workflow/setup.md](workflow/setup.md) for installation and configuration.
|
||||
|
||||
### Phase 4: Manual Validation
|
||||
|
||||
See [workflow/manual-validation.md](workflow/manual-validation.md) for keyboard and screen reader testing.
|
||||
|
||||
## Reference
|
||||
|
||||
- [Severity Rubric](reference/severity-rubric.md) - Impact x Likelihood calculation
|
||||
- [MUI Framework Awareness](reference/mui-awareness.md) - Built-in accessibility features
|
||||
|
||||
## Common False Positives to Avoid
|
||||
|
||||
| Component | Built-in Behavior | Don't Flag |
|
||||
|-----------|-------------------|------------|
|
||||
| MUI `<SvgIcon>` | Auto `aria-hidden="true"` | Icons without titleAccess |
|
||||
| MUI `<Alert>` | Default `role="alert"` | Missing role attribute |
|
||||
| MUI `<Button>` | 36.5px min height | Target size < 44px |
|
||||
| MUI `<TextField>` | Auto label association | Missing label |
|
||||
| MUI `<Autocomplete>` | Manages ARIA attrs | Missing aria-expanded |
|
||||
|
||||
## Quick Audit Command
|
||||
|
||||
```
|
||||
Run accessibility audit on [component/page] following WCAG 2.2 AA standards
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `codebase-auditor` - General code quality analysis
|
||||
- `bulletproof-react-auditor` - React architecture review
|
||||
@@ -0,0 +1,83 @@
|
||||
# MUI Framework Awareness
|
||||
|
||||
MUI components have built-in accessibility features. Audit rules MUST account for framework defaults to avoid false positives.
|
||||
|
||||
## Component Defaults
|
||||
|
||||
### SvgIcon
|
||||
- **Behavior**: Automatically adds `aria-hidden="true"` when `titleAccess` prop is undefined
|
||||
- **Source**: `node_modules/@mui/material/SvgIcon/SvgIcon.js`
|
||||
|
||||
**Rule**: Do NOT flag MUI icons as missing aria-hidden unless titleAccess is set
|
||||
|
||||
```tsx
|
||||
// Only flag if titleAccess is set (should have aria-label or be visible):
|
||||
<SvgIcon titleAccess="Icon name" />
|
||||
|
||||
// Do NOT flag (auto aria-hidden):
|
||||
<SearchIcon />
|
||||
<Timeline />
|
||||
```
|
||||
|
||||
### Alert
|
||||
- **Behavior**: Defaults to `role="alert"` (assertive live region)
|
||||
|
||||
**Rule**: Do NOT recommend adding `role="alert"` - it's already there
|
||||
|
||||
```tsx
|
||||
// Only suggest role="status" if polite announcement is more appropriate:
|
||||
<Alert severity="success" role="status">Item saved</Alert>
|
||||
```
|
||||
|
||||
### Button
|
||||
- **Behavior**: Has minimum 36.5px height by default
|
||||
|
||||
**Rule**: Usually meets 24x24px target size requirement
|
||||
|
||||
```tsx
|
||||
// Only flag if size="small" or custom sx reduces below 24px:
|
||||
<Button size="small" sx={{ minHeight: '20px' }} /> // Flag this
|
||||
<Button>Normal</Button> // Don't flag
|
||||
```
|
||||
|
||||
### TextField
|
||||
- **Behavior**: Automatically associates label with input via id
|
||||
|
||||
**Rule**: Do NOT flag as missing label if `label` prop is provided
|
||||
|
||||
```tsx
|
||||
// This is accessible (auto-associated):
|
||||
<TextField label="Email" />
|
||||
|
||||
// Only flag if no label and no aria-label:
|
||||
<TextField /> // Flag this
|
||||
```
|
||||
|
||||
### Autocomplete
|
||||
- **Behavior**: Manages `aria-expanded`, `aria-controls`, `aria-activedescendant`
|
||||
|
||||
**Rule**: Do NOT flag ARIA attributes - they're managed by component
|
||||
|
||||
```tsx
|
||||
// All ARIA is handled internally:
|
||||
<Autocomplete options={options} renderInput={(params) => <TextField {...params} />} />
|
||||
```
|
||||
|
||||
## False Positive Checklist
|
||||
|
||||
Before flagging a MUI component violation:
|
||||
|
||||
1. [ ] Check if MUI provides default accessibility behavior
|
||||
2. [ ] Verify the violation exists in rendered output (use browser DevTools)
|
||||
3. [ ] Test with actual screen reader to confirm issue
|
||||
4. [ ] Check MUI documentation for accessibility notes
|
||||
|
||||
## Common False Positives
|
||||
|
||||
| Automated Finding | Why It's False | Reality |
|
||||
|-------------------|----------------|---------|
|
||||
| "Icon missing aria-hidden" | MUI adds it automatically | Check rendered HTML |
|
||||
| "Alert missing role" | Default is role="alert" | Only change if polite needed |
|
||||
| "Button too small" | 36.5px default height | Check actual rendered size |
|
||||
| "Input missing label" | TextField manages labels | Check for label prop |
|
||||
| "Missing aria-expanded" | Autocomplete manages it | Check rendered state |
|
||||
@@ -0,0 +1,80 @@
|
||||
# Severity Rubric
|
||||
|
||||
## Core Principle
|
||||
|
||||
**Severity = Impact x Likelihood**, NOT WCAG conformance level.
|
||||
|
||||
- Level A vs AA is a *conformance tier*, not a risk rating
|
||||
- A Level A failure can be LOW severity (decorative image missing alt)
|
||||
- A Level AA failure can be CRITICAL (focus outline removed)
|
||||
|
||||
## Severity Levels
|
||||
|
||||
### Critical
|
||||
- **Description**: Completely blocks access for users with disabilities
|
||||
- **Impact**: Prevents task completion
|
||||
- **Examples**:
|
||||
- Keyboard trap preventing navigation (2.1.2, Level A)
|
||||
- Missing alt text on primary action image (1.1.1, Level A)
|
||||
- Form submission inaccessible via keyboard (2.1.1, Level A)
|
||||
- Focus outline removed from focusable elements (2.4.7, Level AA)
|
||||
|
||||
### High
|
||||
- **Description**: Significantly degrades experience or blocks common workflows
|
||||
- **Impact**: Makes tasks difficult or requires workarounds
|
||||
- **Examples**:
|
||||
- No skip navigation on complex site (2.4.1, Level A)
|
||||
- Poor contrast on primary CTA button (1.4.3, Level AA)
|
||||
- Missing error suggestions on required form (3.3.3, Level AA)
|
||||
- Touch targets too small on mobile (2.5.8, Level AA)
|
||||
|
||||
### Medium
|
||||
- **Description**: Minor usability impact, affects subset of users
|
||||
- **Impact**: Causes confusion or requires extra effort
|
||||
- **Examples**:
|
||||
- Decorative icon not hidden but in acceptable context (1.1.1, Level A)
|
||||
- Link text needs slight improvement for clarity (2.4.4, Level A)
|
||||
- Missing autocomplete on optional field (1.3.5, Level AA)
|
||||
|
||||
### Low
|
||||
- **Description**: Best practice enhancement, minimal user impact
|
||||
- **Impact**: Nice-to-have improvement
|
||||
- **Examples**:
|
||||
- Could add tooltips for better UX (not required)
|
||||
- Page title could be more descriptive (2.4.2, Level A - but functional)
|
||||
|
||||
## Calculation Guide
|
||||
|
||||
### Impact Assessment
|
||||
| Level | Description | Severity Modifier |
|
||||
|-------|-------------|-------------------|
|
||||
| Blocker | Prevents access | Critical/High |
|
||||
| Degraded | Makes difficult | High/Medium |
|
||||
| Friction | Adds effort | Medium/Low |
|
||||
| Minor | Barely noticeable | Low |
|
||||
|
||||
### Likelihood Assessment
|
||||
| Level | Description | Severity Modifier |
|
||||
|-------|-------------|-------------------|
|
||||
| Core flow | All users hit it | Increase severity |
|
||||
| Common | Many users hit it | Base severity |
|
||||
| Edge case | Few users hit it | Decrease severity |
|
||||
| Rare | Almost never | Low |
|
||||
|
||||
## Examples
|
||||
|
||||
### Same Criterion, Different Severity
|
||||
|
||||
**Missing alt text (1.1.1, Level A)**:
|
||||
- Hero image: Impact=Blocker, Likelihood=All users → **CRITICAL**
|
||||
- Decorative footer icon: Impact=Minor, Likelihood=Rare → **LOW**
|
||||
|
||||
**No skip link (2.4.1, Level A)**:
|
||||
- 3-item navigation: Impact=Friction, Likelihood=Common → **MEDIUM**
|
||||
- 50-item navigation: Impact=Degraded, Likelihood=All users → **HIGH**
|
||||
|
||||
**Poor contrast (1.4.3, Level AA)**:
|
||||
- Primary CTA button: **CRITICAL**
|
||||
- Body text: **HIGH**
|
||||
- Footer link: **MEDIUM**
|
||||
- Decorative text: **LOW**
|
||||
@@ -0,0 +1,125 @@
|
||||
# Phase 4: Manual Validation
|
||||
|
||||
These checks CANNOT be automated and require human judgment.
|
||||
|
||||
## 1. Color Contrast Validation
|
||||
|
||||
**Tool**: [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
||||
|
||||
### Process
|
||||
1. Extract all colors from theme configuration
|
||||
2. Calculate contrast ratios for each text/background pair
|
||||
3. Document results in gap report
|
||||
|
||||
### Requirements
|
||||
| Element Type | Minimum Ratio |
|
||||
|--------------|---------------|
|
||||
| Normal text (< 18pt) | 4.5:1 |
|
||||
| Large text (>= 18pt or 14pt bold) | 3:1 |
|
||||
| UI components | 3:1 |
|
||||
| Focus indicators | 3:1 |
|
||||
|
||||
### Severity by Element
|
||||
- Primary CTA button low contrast = **CRITICAL**
|
||||
- Body text low contrast = **HIGH**
|
||||
- Footer link low contrast = **MEDIUM**
|
||||
- Decorative text low contrast = **LOW**
|
||||
|
||||
## 2. Keyboard Navigation Testing
|
||||
|
||||
### Basic Test
|
||||
1. Start at top of page
|
||||
2. Press Tab repeatedly through all interactive elements
|
||||
3. Verify:
|
||||
- [ ] Logical order (left-to-right, top-to-bottom)
|
||||
- [ ] No keyboard traps (can always Tab away)
|
||||
- [ ] All functionality accessible
|
||||
- [ ] Focus indicator visible on every element
|
||||
|
||||
### Key Combinations to Test
|
||||
| Key | Expected Behavior |
|
||||
|-----|-------------------|
|
||||
| Tab | Move to next focusable element |
|
||||
| Shift+Tab | Move to previous focusable element |
|
||||
| Enter | Activate buttons/links |
|
||||
| Space | Activate buttons, toggle checkboxes |
|
||||
| Escape | Close modals/menus |
|
||||
| Arrow keys | Navigate within components (menus, tabs) |
|
||||
|
||||
### Common Keyboard Traps
|
||||
- Modal dialogs without Escape handling
|
||||
- Date pickers without keyboard support
|
||||
- Custom dropdowns that don't cycle
|
||||
|
||||
## 3. Screen Reader Testing
|
||||
|
||||
### Recommended Tools
|
||||
- **Mac**: VoiceOver (built-in, Cmd+F5)
|
||||
- **Windows**: NVDA (free), JAWS (paid)
|
||||
- **iOS**: VoiceOver (built-in)
|
||||
- **Android**: TalkBack (built-in)
|
||||
|
||||
### What to Test
|
||||
1. **Landmarks**: Header, nav, main, footer announced
|
||||
2. **Headings**: Logical hierarchy (h1 → h2 → h3)
|
||||
3. **Forms**: Labels announced, errors read
|
||||
4. **Dynamic content**: Status messages announced
|
||||
5. **Images**: Alt text read appropriately
|
||||
|
||||
### VoiceOver Commands (Mac)
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| VO + Right Arrow | Next element |
|
||||
| VO + Left Arrow | Previous element |
|
||||
| VO + U | Open rotor (landmarks, headings, links) |
|
||||
| VO + Space | Activate |
|
||||
|
||||
## 4. Zoom and Reflow Testing
|
||||
|
||||
### 200% Zoom Test
|
||||
1. Browser zoom to 200%
|
||||
2. Verify:
|
||||
- [ ] No horizontal scrolling
|
||||
- [ ] No text truncation
|
||||
- [ ] No overlapping elements
|
||||
- [ ] All functionality accessible
|
||||
|
||||
### 320px Width Test (Mobile Reflow)
|
||||
1. Resize browser to 320px width
|
||||
2. Verify:
|
||||
- [ ] Content reflows to single column
|
||||
- [ ] No horizontal scroll
|
||||
- [ ] Touch targets still accessible
|
||||
- [ ] Text remains readable
|
||||
|
||||
## 5. WCAG Interpretation Decisions
|
||||
|
||||
Some criteria require human judgment:
|
||||
|
||||
### 2.4.5 Multiple Ways
|
||||
- **Question**: Is this a "set of Web pages"?
|
||||
- **If < 3 pages**: Likely exempt
|
||||
- **If >= 3 pages**: Need 2+ navigation methods
|
||||
|
||||
### 3.2.6 Consistent Help
|
||||
- **Question**: Does a help mechanism exist?
|
||||
- **If no help exists**: Compliant (no requirement)
|
||||
- **If help exists**: Must be consistently placed
|
||||
|
||||
### 1.3.5 Identify Input Purpose
|
||||
- **Question**: Is this collecting user data from the 53 specified purposes?
|
||||
- Search inputs: **NOT** in scope
|
||||
- User email/phone: **IN** scope
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] All color combinations checked against contrast requirements
|
||||
- [ ] Full keyboard navigation test completed
|
||||
- [ ] Screen reader testing with at least one tool
|
||||
- [ ] 200% zoom test passed
|
||||
- [ ] 320px reflow test passed
|
||||
- [ ] Applicability decisions documented
|
||||
|
||||
## Next Step
|
||||
|
||||
Proceed with Report Generation (JSON + Markdown outputs).
|
||||
89
skills/analysis/accessibility-audit/workflow/setup.md
Normal file
89
skills/analysis/accessibility-audit/workflow/setup.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Phase 1: Setup & Preparation
|
||||
|
||||
## Required Tooling Installation
|
||||
|
||||
### Static Analysis (Required)
|
||||
```bash
|
||||
npm install --save-dev eslint-plugin-jsx-a11y
|
||||
```
|
||||
|
||||
Configure `.eslintrc.js`:
|
||||
```javascript
|
||||
module.exports = {
|
||||
extends: ['plugin:jsx-a11y/recommended'],
|
||||
// ... other config
|
||||
};
|
||||
```
|
||||
|
||||
### Runtime Analysis (Required)
|
||||
```bash
|
||||
npm install --save-dev jest-axe @axe-core/react
|
||||
```
|
||||
|
||||
### E2E Analysis (Required)
|
||||
```bash
|
||||
npm install --save-dev @axe-core/playwright
|
||||
```
|
||||
|
||||
### Optional Tools
|
||||
```bash
|
||||
npm install --save-dev @storybook/addon-a11y pa11y-ci
|
||||
```
|
||||
|
||||
## Verification Commands
|
||||
|
||||
```bash
|
||||
# Verify installations
|
||||
npm list eslint-plugin-jsx-a11y jest-axe @axe-core/playwright
|
||||
|
||||
# Check ESLint config
|
||||
grep -l "jsx-a11y" .eslintrc* 2>/dev/null || echo "jsx-a11y not configured"
|
||||
```
|
||||
|
||||
## Output Directory Setup
|
||||
|
||||
```bash
|
||||
mkdir -p docs/accessibility
|
||||
```
|
||||
|
||||
## Prepare Report Templates
|
||||
|
||||
### Gap Report JSON Structure
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"project": "PROJECT_NAME",
|
||||
"auditDate": "YYYY-MM-DD",
|
||||
"auditor": "Claude Code",
|
||||
"protocolVersion": "2.0.0",
|
||||
"wcagVersion": "2.2",
|
||||
"wcagLevel": "AA"
|
||||
},
|
||||
"summary": {
|
||||
"totalCriteria": 60,
|
||||
"passing": 0,
|
||||
"failing": 0,
|
||||
"notApplicable": 0,
|
||||
"compliancePercentage": 0,
|
||||
"severityBreakdown": {
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"low": 0
|
||||
}
|
||||
},
|
||||
"findings": []
|
||||
}
|
||||
```
|
||||
|
||||
## Pre-Audit Checklist
|
||||
|
||||
- [ ] eslint-plugin-jsx-a11y installed and configured
|
||||
- [ ] jest-axe available for component tests
|
||||
- [ ] @axe-core/playwright available for E2E tests
|
||||
- [ ] docs/accessibility/ directory exists
|
||||
- [ ] Project uses React + TypeScript (protocol optimized for this stack)
|
||||
|
||||
## Next Step
|
||||
|
||||
Continue with Static Analysis (ESLint jsx-a11y scan).
|
||||
Reference in New Issue
Block a user