Design System Accessibility Implementation Guidelines¶
WCAG 2.1 AAA Standards and Procedures¶
Version 1.0 - December 2024
Task 47: Comprehensive Accessibility Standards for Design System
Scope: Implementation guidelines for WCAG 2.1 AAA compliance
Table of Contents¶
- Introduction
- Design Token Accessibility Standards
- Component Accessibility Requirements
- Testing Procedures
- Development Workflows
- Content Creation Guidelines
- Quality Assurance Checklist
- Maintenance and Updates
1. Introduction¶
These guidelines establish the standards and procedures for implementing and maintaining WCAG 2.1 AAA accessibility compliance across the Ultimate MkDocs design system. They serve as the authoritative reference for developers, designers, and content creators working with the system.
1.1 Compliance Levels¶
Level | Requirements | Implementation Status |
---|---|---|
WCAG 2.1 A | Basic accessibility | ✅ Complete |
WCAG 2.1 AA | Standard accessibility | ✅ Complete |
WCAG 2.1 AAA | Enhanced accessibility | 🔄 In Implementation |
1.2 Accessibility-First Principles¶
- Universal Design: Solutions work for all users, not just those with disabilities
- Progressive Enhancement: Accessibility features enhance rather than replace base functionality
- Performance Conscious: Accessibility features must not degrade performance
- Future Ready: Implementation anticipates emerging assistive technologies
2. Design Token Accessibility Standards¶
2.1 Color Contrast Requirements¶
AAA Contrast Ratios (Strict Requirements)¶
Normal Text (under 18pt/24px): - Minimum ratio: 7:1 - Recommended ratio: 10:1+ for optimal readability
Large Text (18pt+/24px+ or 14pt+/19px+ bold): - Minimum ratio: 4.5:1 - Recommended ratio: 7:1+ for consistency
Implementation Strategy¶
/* Design Tokens - AAA Compliant Color Pairs */
:root {
/* Primary Palette - AAA Verified */
--token-color-primary-50: #f3e5f5; /* 15.8:1 with dark text ✅ */
--token-color-primary-100: #e1bee7; /* 12.4:1 with dark text ✅ */
--token-color-primary-500: #673ab7; /* 8.2:1 with white text ✅ */
--token-color-primary-700: #512da8; /* 11.6:1 with white text ✅ */
/* Contrast pairs - guaranteed AAA compliance */
--token-contrast-aaa-light: #ffffff;
--token-contrast-aaa-dark: #000000;
--token-contrast-aaa-ratio: 21:1;
/* Semantic Colors - AAA Enhanced */
--token-success-aaa: #2e7d32; /* 7.4:1 with white */
--token-warning-aaa: #e65100; /* 7.1:1 with white */
--token-error-aaa: #c62828; /* 9.1:1 with white */
--token-info-aaa: #1565c0; /* 8.2:1 with white */
}
/* AAA Contrast Mode Override */
.aaa-contrast-mode {
--md-sys-color-primary: var(--token-color-primary-700);
--md-sys-color-secondary: var(--token-warning-aaa);
--md-sys-color-outline: var(--token-contrast-aaa-dark);
--md-sys-color-outline-variant: rgba(0, 0, 0, 0.6);
}
Color Usage Guidelines¶
DO: Always use pre-approved color combinations
/* Approved AAA combinations */
.text-on-primary {
background: var(--token-color-primary-500);
color: var(--token-contrast-aaa-light); /* 8.2:1 ratio ✅ */
}
.text-on-light {
background: var(--token-color-primary-50);
color: var(--token-contrast-aaa-dark); /* 15.8:1 ratio ✅ */
}
DON'T: Create custom color combinations without verification
/* Avoid - not verified for AAA compliance */
.custom-combination {
background: #ba68c8; /* Only 5.1:1 with white - AA only ❌ */
color: #ffffff;
}
2.2 Typography Token Standards¶
Font Size Requirements¶
/* Typography Tokens - AAA Compliant */
:root {
/* Minimum sizes for different contexts */
--token-font-size-minimum: 16px; /* Absolute minimum for body text */
--token-font-size-comfortable: 18px; /* Recommended minimum */
--token-font-size-large: 24px; /* Large text threshold */
/* Line height ratios for optimal readability */
--token-line-height-tight: 1.4; /* Headings only */
--token-line-height-normal: 1.6; /* Body text minimum */
--token-line-height-loose: 1.8; /* Enhanced readability */
/* Letter spacing for improved legibility */
--token-letter-spacing-tight: -0.01em;
--token-letter-spacing-normal: 0em;
--token-letter-spacing-loose: 0.02em;
}
Typography Implementation¶
/* Base typography - AAA standards */
.token-text-body {
font-size: var(--token-font-size-comfortable);
line-height: var(--token-line-height-normal);
letter-spacing: var(--token-letter-spacing-normal);
max-width: 70ch; /* Optimal reading width */
}
.token-text-enhanced {
font-size: var(--token-font-size-comfortable);
line-height: var(--token-line-height-loose);
letter-spacing: var(--token-letter-spacing-loose);
max-width: 60ch; /* Narrower for enhanced readability */
}
/* Responsive scaling - maintains ratios */
@media (max-width: 768px) {
.token-text-body {
font-size: max(var(--token-font-size-minimum), 4vw);
}
}
2.3 Spacing and Layout Tokens¶
Touch Target Standards¶
/* Touch Target Tokens - AAA Compliance */
:root {
--token-touch-target-minimum: 44px; /* WCAG AA minimum */
--token-touch-target-comfortable: 48px; /* AAA recommended */
--token-touch-target-generous: 56px; /* Enhanced accessibility */
/* Spacing between interactive elements */
--token-interactive-spacing: 8px; /* Minimum separation */
--token-interactive-spacing-comfortable: 16px; /* Recommended */
}
/* Interactive element implementation */
.token-interactive {
min-height: var(--token-touch-target-comfortable);
min-width: var(--token-touch-target-comfortable);
margin: var(--token-interactive-spacing-comfortable);
/* Ensure visual target matches interactive area */
position: relative;
}
.token-interactive::before {
content: '';
position: absolute;
inset: calc(var(--token-interactive-spacing) * -1);
/* Extends interactive area beyond visual bounds */
}
2.4 Motion and Animation Tokens¶
Reduced Motion Standards¶
/* Motion Tokens - Accessibility First */
:root {
--token-motion-duration-instant: 0ms;
--token-motion-duration-fast: 150ms;
--token-motion-duration-normal: 300ms;
--token-motion-duration-slow: 500ms;
/* Easing functions - natural and comfortable */
--token-motion-ease-gentle: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--token-motion-ease-accessible: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Accessibility-first motion implementation */
.token-animated {
transition: transform var(--token-motion-duration-normal) var(--token-motion-ease-accessible);
}
/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
.token-animated {
transition-duration: var(--token-motion-duration-instant);
animation-duration: var(--token-motion-duration-instant);
}
}
/* Enhanced motion sensitivity */
@media (prefers-reduced-motion: reduce) {
.token-animated,
.token-animated * {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
transform: none !important;
}
}
3. Component Accessibility Requirements¶
3.1 Button Components¶
Basic Implementation¶
<!-- AAA Button Implementation -->
<button class="token-button"
type="button"
aria-describedby="button-help">
<span class="token-button__text">Save Document</span>
<span class="token-button__icon" aria-hidden="true">💾</span>
</button>
<div id="button-help" class="sr-only">
Saves the current document to your browser's local storage
</div>
CSS Implementation¶
.token-button {
/* Size and spacing */
min-height: var(--token-touch-target-comfortable);
padding: 12px 24px;
/* Typography */
font-size: var(--token-font-size-comfortable);
line-height: var(--token-line-height-normal);
/* Colors - AAA compliant */
background: var(--token-color-primary-500);
color: var(--token-contrast-aaa-light);
/* Focus management */
outline: none;
border: 2px solid transparent;
/* Interaction feedback */
transition: all var(--token-motion-duration-fast) var(--token-motion-ease-accessible);
}
.token-button:focus-visible {
outline: 3px solid var(--token-color-secondary-500);
outline-offset: 3px;
box-shadow: 0 0 0 6px rgba(255, 193, 7, 0.2);
}
.token-button:hover:not(:disabled) {
background: var(--token-color-primary-700);
transform: translateY(-1px);
}
.token-button:active {
transform: translateY(0);
}
.token-button:disabled {
background: var(--token-color-neutral-40);
color: var(--token-color-neutral-60);
cursor: not-allowed;
}
JavaScript Enhancement¶
class AccessibleButton {
constructor(element) {
this.element = element;
this.setupAccessibility();
}
setupAccessibility() {
// Enhanced keyboard support
this.element.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.handleActivation();
}
});
// Screen reader announcements
this.element.addEventListener('click', () => {
this.announceAction();
});
}
handleActivation() {
if (!this.element.disabled) {
this.element.click();
}
}
announceAction() {
const action = this.element.dataset.action || 'activated';
this.announceToScreenReader(`Button ${action}`);
}
announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('aria-live', 'polite');
announcement.setAttribute('aria-atomic', 'true');
announcement.className = 'sr-only';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => announcement.remove(), 1000);
}
}
3.2 Form Components¶
Input Field Implementation¶
<!-- AAA Form Input Implementation -->
<div class="token-form-field">
<label for="email-input" class="token-label">
Email Address
<span class="token-required" aria-label="required">*</span>
</label>
<input type="email"
id="email-input"
class="token-input"
aria-describedby="email-help email-error"
aria-required="true"
autocomplete="email">
<div id="email-help" class="token-help-text">
We'll never share your email address
</div>
<div id="email-error" class="token-error-text" role="alert" aria-live="polite">
<!-- Error messages appear here -->
</div>
</div>
Form CSS Implementation¶
.token-form-field {
margin-bottom: var(--token-space-6);
}
.token-label {
display: block;
font-size: var(--token-font-size-comfortable);
font-weight: 600;
color: var(--token-color-neutral-90);
margin-bottom: var(--token-space-2);
}
.token-input {
width: 100%;
min-height: var(--token-touch-target-comfortable);
padding: 12px 16px;
/* Typography */
font-size: var(--token-font-size-comfortable);
line-height: var(--token-line-height-normal);
/* Colors - AAA compliant */
background: var(--token-color-neutral-0);
color: var(--token-color-neutral-90);
border: 2px solid var(--token-color-neutral-40);
/* Focus management */
outline: none;
transition: border-color var(--token-motion-duration-fast) var(--token-motion-ease-accessible);
}
.token-input:focus {
border-color: var(--token-color-primary-500);
box-shadow: 0 0 0 3px rgba(103, 58, 183, 0.2);
}
.token-input:invalid {
border-color: var(--token-error-aaa);
}
.token-help-text {
font-size: var(--token-font-size-sm);
color: var(--token-color-neutral-70);
margin-top: var(--token-space-1);
}
.token-error-text {
font-size: var(--token-font-size-sm);
color: var(--token-error-aaa);
margin-top: var(--token-space-1);
font-weight: 500;
}
.token-required {
color: var(--token-error-aaa);
margin-left: var(--token-space-1);
}
3.3 Navigation Components¶
Accessible Navigation Implementation¶
<!-- AAA Navigation Implementation -->
<nav class="token-navigation" role="navigation" aria-label="Main navigation">
<div class="token-nav-container">
<a href="#main-content" class="token-skip-link">Skip to main content</a>
<ul class="token-nav-list" role="menubar">
<li role="none">
<a href="/"
class="token-nav-link"
role="menuitem"
aria-current="page">
Home
</a>
</li>
<li role="none">
<button class="token-nav-button"
role="menuitem"
aria-expanded="false"
aria-haspopup="true"
aria-controls="features-menu">
Features
<span class="token-nav-indicator" aria-hidden="true">▼</span>
</button>
<ul id="features-menu"
class="token-submenu"
role="menu"
aria-label="Features submenu">
<li role="none">
<a href="/code-blocks"
class="token-submenu-link"
role="menuitem">
Code Blocks
</a>
</li>
<!-- Additional submenu items -->
</ul>
</li>
</ul>
</div>
</nav>
Navigation CSS¶
.token-navigation {
background: var(--token-color-primary-500);
color: var(--token-contrast-aaa-light);
}
.token-skip-link {
position: absolute;
top: -40px;
left: 6px;
background: var(--token-color-primary-700);
color: var(--token-contrast-aaa-light);
padding: 8px;
text-decoration: none;
transform: translateY(-100%);
transition: transform var(--token-motion-duration-normal);
}
.token-skip-link:focus {
transform: translateY(0);
z-index: 10000;
}
.token-nav-list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.token-nav-link,
.token-nav-button {
display: flex;
align-items: center;
min-height: var(--token-touch-target-generous);
padding: 0 var(--token-space-4);
color: inherit;
text-decoration: none;
border: none;
background: transparent;
cursor: pointer;
/* Focus management */
outline: none;
position: relative;
}
.token-nav-link:focus-visible,
.token-nav-button:focus-visible {
background: rgba(255, 255, 255, 0.1);
outline: 2px solid var(--token-color-secondary-500);
outline-offset: -2px;
}
.token-submenu {
position: absolute;
top: 100%;
left: 0;
background: var(--token-color-primary-600);
list-style: none;
margin: 0;
padding: var(--token-space-2) 0;
min-width: 200px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
/* Hidden by default */
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all var(--token-motion-duration-fast) var(--token-motion-ease-accessible);
}
.token-nav-button[aria-expanded="true"] + .token-submenu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
3.4 Modal and Dialog Components¶
Modal Implementation¶
<!-- AAA Modal Implementation -->
<div class="token-modal"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
aria-describedby="modal-description">
<div class="token-modal-backdrop" aria-hidden="true"></div>
<div class="token-modal-container">
<div class="token-modal-header">
<h2 id="modal-title" class="token-modal-title">
Confirm Action
</h2>
<button class="token-modal-close"
aria-label="Close dialog"
type="button">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="token-modal-body">
<p id="modal-description">
Are you sure you want to delete this item? This action cannot be undone.
</p>
</div>
<div class="token-modal-footer">
<button class="token-button token-button--secondary" type="button">
Cancel
</button>
<button class="token-button token-button--danger" type="button">
Delete
</button>
</div>
</div>
</div>
Modal JavaScript¶
class AccessibleModal {
constructor(element) {
this.element = element;
this.previousFocus = null;
this.focusableElements = null;
this.setupAccessibility();
}
setupAccessibility() {
// Focus management
this.element.addEventListener('keydown', (e) => this.handleKeydown(e));
// Close button functionality
const closeButton = this.element.querySelector('.token-modal-close');
closeButton?.addEventListener('click', () => this.close());
// Backdrop click to close
const backdrop = this.element.querySelector('.token-modal-backdrop');
backdrop?.addEventListener('click', () => this.close());
}
open() {
// Store current focus
this.previousFocus = document.activeElement;
// Show modal
this.element.style.display = 'flex';
// Prevent body scroll
document.body.style.overflow = 'hidden';
// Find focusable elements
this.focusableElements = this.element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
// Focus first element
if (this.focusableElements.length > 0) {
this.focusableElements[0].focus();
}
// Announce to screen reader
this.announceToScreenReader('Dialog opened');
}
close() {
// Hide modal
this.element.style.display = 'none';
// Restore body scroll
document.body.style.overflow = '';
// Restore focus
if (this.previousFocus) {
this.previousFocus.focus();
}
// Announce to screen reader
this.announceToScreenReader('Dialog closed');
}
handleKeydown(e) {
// Close on Escape
if (e.key === 'Escape') {
this.close();
return;
}
// Trap focus
if (e.key === 'Tab') {
this.trapFocus(e);
}
}
trapFocus(e) {
const firstElement = this.focusableElements[0];
const lastElement = this.focusableElements[this.focusableElements.length - 1];
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('aria-live', 'assertive');
announcement.setAttribute('aria-atomic', 'true');
announcement.className = 'sr-only';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => announcement.remove(), 1000);
}
}
4. Testing Procedures¶
4.1 Automated Testing¶
Setup and Tools¶
# Install accessibility testing tools
npm install --save-dev @axe-core/cli @axe-core/playwright pa11y
Automated Test Implementation¶
// tests/accessibility.test.js
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test.describe('Accessibility Tests', () => {
test('should not have any automatically detectable accessibility issues', async ({ page }) => {
await page.goto('/');
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag2aaa'])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
test('should support keyboard navigation', async ({ page }) => {
await page.goto('/');
// Test tab navigation
await page.keyboard.press('Tab');
await expect(page.locator(':focus')).toBeVisible();
// Test skip link
await page.keyboard.press('Tab');
const skipLink = page.locator('.token-skip-link:focus');
await expect(skipLink).toBeVisible();
// Test Enter key activation
await page.keyboard.press('Enter');
await expect(page.locator('#main-content')).toBeFocused();
});
test('should provide proper focus indicators', async ({ page }) => {
await page.goto('/');
const buttons = page.locator('button');
const buttonCount = await buttons.count();
for (let i = 0; i < buttonCount; i++) {
await buttons.nth(i).focus();
// Check focus indicator is visible
const focusedButton = buttons.nth(i);
await expect(focusedButton).toHaveCSS('outline-width', '3px');
}
});
});
Color Contrast Testing¶
// tests/color-contrast.test.js
import { test, expect } from '@playwright/test';
test.describe('Color Contrast Tests', () => {
test('should meet AAA contrast requirements', async ({ page }) => {
await page.goto('/');
// Test all text elements for AAA compliance
const textElements = await page.locator('p, h1, h2, h3, h4, h5, h6, a, button, span').all();
for (const element of textElements) {
const styles = await element.evaluate((el) => {
const computed = window.getComputedStyle(el);
return {
color: computed.color,
backgroundColor: computed.backgroundColor,
fontSize: computed.fontSize
};
});
const contrastRatio = calculateContrastRatio(styles.color, styles.backgroundColor);
const fontSize = parseFloat(styles.fontSize);
if (fontSize >= 24 || (fontSize >= 19 && element.getAttribute('bold'))) {
// Large text - AAA requires 4.5:1
expect(contrastRatio).toBeGreaterThanOrEqual(4.5);
} else {
// Normal text - AAA requires 7:1
expect(contrastRatio).toBeGreaterThanOrEqual(7);
}
}
});
});
function calculateContrastRatio(foreground, background) {
// Simplified contrast ratio calculation
// In practice, use a proper color library like 'color' or 'chroma-js'
const rgb1 = parseRgb(foreground);
const rgb2 = parseRgb(background);
const lum1 = getLuminance(rgb1);
const lum2 = getLuminance(rgb2);
const brightest = Math.max(lum1, lum2);
const darkest = Math.min(lum1, lum2);
return (brightest + 0.05) / (darkest + 0.05);
}
4.2 Manual Testing Procedures¶
Screen Reader Testing Checklist¶
## Screen Reader Testing Protocol
### Pre-Test Setup
- [ ] Test with NVDA (Windows), VoiceOver (Mac), and JAWS (Windows)
- [ ] Clear browser cache and disable extensions
- [ ] Use keyboard-only navigation during testing
### Content Structure Testing
- [ ] Page title is read correctly
- [ ] Heading structure is logical (h1 → h2 → h3)
- [ ] Landmarks are properly announced (main, nav, aside, footer)
- [ ] Lists are announced as lists with item counts
- [ ] Tables have proper headers and captions
### Interactive Element Testing
- [ ] All buttons announce their purpose and state
- [ ] Form fields have associated labels
- [ ] Required fields are announced as required
- [ ] Error messages are read when they appear
- [ ] Modal dialogs trap focus and announce content
### Navigation Testing
- [ ] Skip links work and are announced
- [ ] Tab order is logical and predictable
- [ ] Current page/section is identified
- [ ] Breadcrumbs provide context
- [ ] Search functionality is accessible
### Media and Images Testing
- [ ] Decorative images are ignored (aria-hidden="true")
- [ ] Informative images have descriptive alt text
- [ ] Complex images have long descriptions
- [ ] Icons used with text are properly labeled
Keyboard Navigation Testing¶
## Keyboard Navigation Testing Protocol
### Basic Navigation
- [ ] Tab: Moves to next interactive element
- [ ] Shift+Tab: Moves to previous interactive element
- [ ] Enter: Activates buttons and links
- [ ] Space: Activates buttons, checks checkboxes
- [ ] Arrow keys: Navigate within components (tabs, menus)
- [ ] Escape: Closes modals and dropdowns
### Advanced Navigation
- [ ] Home/End: Jump to beginning/end of components
- [ ] Page Up/Down: Scroll content in large containers
- [ ] Letters: Navigate by first letter in lists/menus
- [ ] F6: Move between page regions
### Focus Management
- [ ] Focus is visible on all interactive elements
- [ ] Focus never disappears or gets trapped
- [ ] Modal dialogs trap focus appropriately
- [ ] Focus returns to trigger element after modal closes
- [ ] Skip links are functional and properly positioned
4.3 User Testing with Assistive Technology¶
Testing Protocol¶
## AT User Testing Protocol
### Participant Requirements
- Minimum 6 months experience with their primary AT
- Mix of screen reader, voice recognition, and switch users
- Range of expertise levels (beginner to advanced)
### Testing Scenarios
1. **First-time visitor**: Find specific information
2. **Return visitor**: Complete a typical task
3. **Power user**: Use advanced features
4. **Error recovery**: Handle and correct mistakes
### Data Collection
- Task completion rates
- Time to complete tasks
- Number of errors/obstacles
- User satisfaction ratings
- Specific pain points and suggestions
### Success Criteria
- 95% task completion rate
- Average satisfaction score ≥ 4/5
- No critical barriers identified
- Performance within 20% of non-AT users
5. Development Workflows¶
5.1 Accessibility-First Development Process¶
Pre-Development Phase¶
## Design Review Checklist
### Visual Design Review
- [ ] Color combinations meet AAA contrast requirements
- [ ] Text is minimum 16px (18px recommended)
- [ ] Interactive elements are minimum 44px (48px recommended)
- [ ] Focus indicators are clearly visible
- [ ] Information doesn't rely solely on color
### Information Architecture Review
- [ ] Heading hierarchy is logical
- [ ] Content flows in reading order
- [ ] Related content is grouped appropriately
- [ ] Navigation is consistent across pages
- [ ] Error states and success states are defined
### Interaction Design Review
- [ ] All functionality available via keyboard
- [ ] Error prevention strategies are in place
- [ ] Help text and instructions are provided
- [ ] Time limits can be extended or disabled
- [ ] Motion can be reduced or disabled
Development Phase¶
// Accessibility development workflow
class AccessibilityWorkflow {
constructor() {
this.setupLinting();
this.setupTesting();
this.setupValidation();
}
setupLinting() {
// ESLint accessibility rules
const eslintConfig = {
extends: ['plugin:jsx-a11y/recommended'],
rules: {
'jsx-a11y/no-autofocus': 'error',
'jsx-a11y/no-distracting-elements': 'error',
'jsx-a11y/anchor-has-content': 'error',
'jsx-a11y/aria-role': 'error',
'jsx-a11y/img-redundant-alt': 'error',
'jsx-a11y/label-has-associated-control': 'error',
'jsx-a11y/no-noninteractive-element-interactions': 'error'
}
};
}
setupTesting() {
// Automated accessibility testing in CI/CD
const testConfig = {
'accessibility': {
'axe-core': true,
'pa11y': true,
'lighthouse': true
},
'thresholds': {
'axe-violations': 0,
'contrast-ratio': 7.0,
'lighthouse-a11y': 100
}
};
}
setupValidation() {
// Real-time validation during development
this.validateOnChange();
this.validateOnBuild();
}
validateOnChange() {
// Run accessibility checks on file changes
const watcher = new FileWatcher();
watcher.on('change', (file) => {
if (file.endsWith('.html') || file.endsWith('.css') || file.endsWith('.js')) {
this.runAccessibilityChecks(file);
}
});
}
runAccessibilityChecks(file) {
return Promise.all([
this.checkColorContrast(file),
this.checkHeadingStructure(file),
this.checkARIAUsage(file),
this.checkKeyboardAccess(file)
]);
}
}
5.2 Code Review Guidelines¶
Accessibility Code Review Checklist¶
## Code Review - Accessibility Focus
### HTML Structure Review
- [ ] Semantic HTML elements used appropriately
- [ ] Heading hierarchy is logical (no skipped levels)
- [ ] Form fields have associated labels
- [ ] Images have appropriate alt text or aria-hidden
- [ ] ARIA attributes are used correctly
### CSS Review
- [ ] Focus indicators are clearly visible
- [ ] Color contrast meets AAA requirements
- [ ] Text is scalable and readable
- [ ] Layout works at 200% zoom
- [ ] Animations respect prefers-reduced-motion
### JavaScript Review
- [ ] Keyboard event handlers are implemented
- [ ] Focus management is proper in dynamic content
- [ ] ARIA live regions are used for status updates
- [ ] Error handling provides clear feedback
- [ ] Progressive enhancement is maintained
### Testing Evidence Required
- [ ] Automated test results attached
- [ ] Manual keyboard testing completed
- [ ] Screen reader testing notes provided
- [ ] Color contrast verification included
5.3 Continuous Integration Setup¶
GitHub Actions Workflow¶
# .github/workflows/accessibility.yml
name: Accessibility Testing
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
accessibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Run axe-core accessibility tests
run: npm run test:a11y
- name: Run Pa11y accessibility scan
run: npx pa11y-ci --sitemap http://localhost:3000/sitemap.xml
- name: Run Lighthouse accessibility audit
run: |
npm install -g @lhci/cli
lhci autorun
- name: Check color contrast
run: npm run test:contrast
- name: Validate ARIA usage
run: npm run test:aria
- name: Upload accessibility report
uses: actions/upload-artifact@v3
if: failure()
with:
name: accessibility-report
path: reports/accessibility/
6. Content Creation Guidelines¶
6.1 Writing for Accessibility¶
Plain Language Standards¶
## Writing Guidelines for AAA Compliance
### Reading Level Requirements
- Target: 8th grade reading level or lower
- Use simple, common words instead of complex alternatives
- Keep sentences under 20 words
- Use active voice when possible
### Content Structure
- Use descriptive headings that summarize content
- Break up long paragraphs (max 3-4 sentences)
- Use bulleted or numbered lists for series
- Provide glossaries for technical terms
### Link and Button Text
- Make link text descriptive ("Download the accessibility guide" not "Click here")
- Avoid "Read more" or "Learn more" without context
- Button text should describe the action ("Save document" not "Submit")
- Include file type and size for downloads ("PDF, 1.2MB")
Example Content Transformation¶
<!-- Before: Complex, unclear -->
The implementation of responsive design methodologies in conjunction with
accessibility best practices facilitates the optimization of user experience
across diverse technological platforms and assistive technology configurations.
<!-- After: Simple, clear -->
Responsive design works with accessibility features to help all users.
This includes people who use:
- Screen readers
- Voice recognition software
- Keyboard navigation
- Mobile devices
These features make websites easier to use for everyone.
6.2 Alternative Text Guidelines¶
Image Alt Text Standards¶
<!-- Decorative images -->
<img loading="lazy" src="decorative-border.svg" alt="" aria-hidden="true">
<!-- Informative images -->
<img loading="lazy" src="sales-chart.png"
alt="Sales increased 25% from Q1 to Q2, rising from $100k to $125k">
<!-- Complex images with long description -->
<img loading="lazy" src="org-chart.png"
alt="Company organizational chart showing reporting structure"
longdesc="#org-chart-description">
<div id="org-chart-description">
<h3>Organizational Chart Details</h3>
<p>The CEO reports to the Board of Directors. Under the CEO are three VPs...</p>
</div>
<!-- Functional images (buttons, links) -->
<button>
<img loading="lazy" src="save-icon.svg" alt="">
Save Document
</button>
<!-- Images of text (avoid when possible) -->
<img loading="lazy" src="company-logo-text.png" alt="Ultimate MkDocs - Documentation Excellence">
6.3 Form Design Guidelines¶
Accessible Form Implementation¶
<!-- Complete accessible form example -->
<form class="token-form" novalidate>
<fieldset>
<legend>Contact Information</legend>
<!-- Text input with all accessibility features -->
<div class="token-form-field">
<label for="full-name" class="token-label">
Full Name
<span class="token-required" aria-label="required">*</span>
</label>
<input type="text"
id="full-name"
name="fullName"
class="token-input"
aria-describedby="name-help name-error"
aria-required="true"
autocomplete="name"
spellcheck="false">
<div id="name-help" class="token-help-text">
Enter your first and last name
</div>
<div id="name-error" class="token-error-text" role="alert" aria-live="polite">
<!-- Error messages appear here -->
</div>
</div>
<!-- Email with validation -->
<div class="token-form-field">
<label for="email" class="token-label">
Email Address
<span class="token-required" aria-label="required">*</span>
</label>
<input type="email"
id="email"
name="email"
class="token-input"
aria-describedby="email-help email-error"
aria-required="true"
autocomplete="email">
<div id="email-help" class="token-help-text">
We'll use this to send you updates
</div>
<div id="email-error" class="token-error-text" role="alert" aria-live="polite">
<!-- Error messages appear here -->
</div>
</div>
<!-- Checkbox group -->
<fieldset class="token-checkbox-group">
<legend>Notification Preferences</legend>
<div class="token-checkbox-item">
<input type="checkbox" id="notify-updates" name="notifications" value="updates">
<label for="notify-updates">Product updates</label>
</div>
<div class="token-checkbox-item">
<input type="checkbox" id="notify-news" name="notifications" value="news">
<label for="notify-news">Company news</label>
</div>
</fieldset>
</fieldset>
<!-- Submit with clear action -->
<div class="token-form-actions">
<button type="submit" class="token-button token-button--primary">
Submit Contact Form
</button>
<button type="reset" class="token-button token-button--secondary">
Clear Form
</button>
</div>
</form>
7. Quality Assurance Checklist¶
7.1 Pre-Release Accessibility Audit¶
# Complete Accessibility QA Checklist
## Automated Testing
- [ ] axe-core scan passes with 0 violations
- [ ] Pa11y scan passes all pages
- [ ] Lighthouse accessibility score = 100
- [ ] Color contrast validation passes
- [ ] HTML validation passes
- [ ] ARIA validation passes
## Manual Testing
- [ ] Keyboard navigation works completely
- [ ] Screen reader testing completed (NVDA, VoiceOver, JAWS)
- [ ] High contrast mode works properly
- [ ] 200% zoom test passes
- [ ] Mobile accessibility verified
- [ ] Focus indicators are clearly visible
## Content Review
- [ ] Reading level is 8th grade or lower
- [ ] All images have appropriate alt text
- [ ] Headings create logical structure
- [ ] Links and buttons have descriptive text
- [ ] Forms have proper labels and help text
- [ ] Error messages are clear and helpful
## Feature-Specific Testing
- [ ] Modals trap focus properly
- [ ] Dropdowns announce state changes
- [ ] Form validation provides clear feedback
- [ ] Search functionality is accessible
- [ ] Navigation is consistent and predictable
## Performance Impact
- [ ] Accessibility features don't degrade performance
- [ ] Page load time remains acceptable
- [ ] Animation performance respects user preferences
- [ ] Memory usage stays within acceptable limits
7.2 User Acceptance Testing¶
AT User Testing Protocol¶
// User testing session structure
class AccessibilityUserTesting {
constructor() {
this.participants = [
{ type: 'screen-reader', experience: 'expert', tools: ['JAWS', 'NVDA'] },
{ type: 'screen-reader', experience: 'intermediate', tools: ['VoiceOver'] },
{ type: 'voice-control', experience: 'expert', tools: ['Dragon'] },
{ type: 'keyboard-only', experience: 'intermediate', tools: ['keyboard'] },
{ type: 'cognitive', experience: 'beginner', tools: ['zoom', 'reader-mode'] }
];
this.testScenarios = [
'Find specific information on the homepage',
'Navigate to a specific page using the main menu',
'Complete a form submission',
'Use the search functionality',
'Access help or support information'
];
}
conductTesting() {
this.participants.forEach(participant => {
this.testScenarios.forEach(scenario => {
this.runTestScenario(participant, scenario);
});
});
}
runTestScenario(participant, scenario) {
const results = {
participant: participant.type,
scenario: scenario,
startTime: Date.now(),
success: false,
obstacles: [],
feedback: ''
};
// Record testing session
// Measure completion time
// Note any obstacles or confusion
// Collect qualitative feedback
return results;
}
analyzeResults() {
// Calculate success rates
// Identify common obstacles
// Prioritize improvements
// Generate accessibility report
}
}
8. Maintenance and Updates¶
8.1 Ongoing Accessibility Monitoring¶
Continuous Monitoring Setup¶
// Accessibility monitoring service
class AccessibilityMonitoring {
constructor() {
this.setupAutomatedChecks();
this.setupPerformanceMonitoring();
this.setupUserFeedback();
}
setupAutomatedChecks() {
// Daily accessibility scans
this.scheduler.daily(() => {
this.runAccessibilityAudit();
});
// Weekly comprehensive review
this.scheduler.weekly(() => {
this.runComprehensiveAudit();
});
}
setupPerformanceMonitoring() {
// Monitor accessibility feature performance
this.monitor.track('accessibility-features', {
'focus-management': true,
'screen-reader-support': true,
'keyboard-navigation': true,
'color-contrast': true
});
}
setupUserFeedback() {
// Accessibility feedback collection
this.createFeedbackChannel();
this.monitorSupportTickets();
this.analyzeUserBehavior();
}
generateMonthlyReport() {
return {
compliance: this.getComplianceStatus(),
userFeedback: this.summarizeUserFeedback(),
performanceMetrics: this.getPerformanceMetrics(),
recommendations: this.generateRecommendations()
};
}
}
8.2 Update Procedures¶
Accessibility Impact Assessment¶
# Change Impact Assessment Protocol
## Pre-Change Assessment
- [ ] Identify which accessibility features might be affected
- [ ] Review changes against WCAG 2.1 AAA criteria
- [ ] Plan additional testing requirements
- [ ] Update accessibility test suite if needed
## Change Implementation
- [ ] Follow accessibility-first development process
- [ ] Run automated accessibility tests
- [ ] Perform manual verification of affected areas
- [ ] Update documentation as needed
## Post-Change Validation
- [ ] Complete accessibility regression testing
- [ ] Verify no new violations introduced
- [ ] Update accessibility statements if needed
- [ ] Monitor user feedback for accessibility issues
## Documentation Updates
- [ ] Update component documentation
- [ ] Revise implementation guidelines if needed
- [ ] Update training materials
- [ ] Communicate changes to development team
8.3 Team Training and Knowledge Sharing¶
Training Program Structure¶
# Accessibility Training Program
## Level 1: Awareness (All Team Members)
- Basic accessibility principles
- Why accessibility matters
- Common barriers and solutions
- Company accessibility policy
## Level 2: Implementation (Developers, Designers)
- WCAG 2.1 guidelines detailed study
- Hands-on accessibility testing
- Assistive technology overview
- Accessible design patterns
## Level 3: Expert (Accessibility Champions)
- Advanced accessibility techniques
- User research with disabled users
- Accessibility auditing skills
- Training and mentoring others
## Ongoing Education
- Monthly accessibility tips
- Quarterly lunch-and-learns
- Annual accessibility conference attendance
- Regular updates on new guidelines and tools
Conclusion¶
These implementation guidelines provide a comprehensive framework for achieving and maintaining WCAG 2.1 AAA accessibility compliance across the Ultimate MkDocs design system. By following these standards and procedures, teams can ensure that the design system serves all users effectively while maintaining its innovative features and excellent user experience.
Key Success Factors¶
- Standards-Based Approach: All implementations follow established WCAG 2.1 AAA criteria
- Comprehensive Testing: Automated and manual testing procedures ensure thorough coverage
- User-Centered Design: Real user testing validates accessibility effectiveness
- Continuous Improvement: Ongoing monitoring and updates maintain compliance
- Team Education: Training ensures consistent implementation across all team members
Implementation Priority¶
- Phase 1: Implement AAA color contrast standards and enhanced user controls
- Phase 2: Complete component accessibility requirements and testing procedures
- Phase 3: Establish development workflows and quality assurance processes
- Phase 4: Deploy monitoring systems and training programs
By following these guidelines, the design system will achieve industry-leading accessibility while serving as a model for other projects seeking comprehensive inclusive design implementation.
These guidelines are living documents that should be updated as accessibility standards evolve and new requirements emerge. Regular review and updates ensure continued compliance and optimal user experience for all.