Skip to content

Repository files navigation

Enterprise Accessibility Learning Project

A comprehensive React + Vite application demonstrating enterprise-level web accessibility (a11y) implementation, built as a learning resource for understanding WCAG 2.1 AA accessibility standards.

Overview

This project provides a practical implementation of web accessibility concepts. Each component, pattern, and test demonstrates specific accessibility techniques and best practices that can be applied to real-world applications.

Features

  • Semantic HTML Structure: Proper use of landmarks (nav, main, footer, etc.)
  • Accessible Forms: Proper label associations, error handling, and ARIA attributes
  • Focus Management: Client-side routing focus handling and modal focus trapping
  • Screen Reader Support: Optimized for NVDA, VoiceOver, and other assistive technologies
  • Automated Testing: ESLint, jest-axe, and cypress-axe integration
  • Documentation: Comprehensive learning notes and implementation guides

Getting Started

Prerequisites

  • Node.js 18+ and npm
  • A modern browser (Chrome, Firefox, Safari, or Edge)
  • (Optional) Screen reader for testing (NVDA for Windows, VoiceOver for macOS)

Installation

# Install dependencies
npm install

# Start development server
npm run dev

# Open browser to http://localhost:5173

Available Scripts

npm run dev          # Start development server
npm run build        # Build for production
npm run preview      # Preview production build
npm run lint         # Run ESLint with accessibility checks
npm run test         # Run Jest unit tests
npm run test:e2e     # Open Cypress for E2E testing
npm run test:e2e:headless  # Run Cypress tests in headless mode

Project Structure

web-a11y/
├── docs/                    # Learning documentation
│   ├── strategy-and-semantics.md
│   ├── aria-and-screen-readers.md
│   ├── focus-management.md
│   ├── testing-and-processes.md
│   ├── accessibility-checklist.md
│   └── definition-of-done.md
├── src/
│   ├── components/          # Reusable components
│   │   ├── Modal.tsx        # Accessible modal with focus trap
│   │   └── Modal.test.tsx
│   ├── pages/               # Page components
│   │   ├── HomePage.tsx
│   │   ├── FormsPage.tsx    # Form accessibility demo
│   │   └── ModalsPage.tsx   # Modal focus management demo
│   ├── App.tsx              # Main app with routing
│   ├── index.css            # Global styles with a11y utilities
│   └── setupTests.ts        # Jest configuration
├── cypress/
│   ├── e2e/
│   │   └── accessibility.cy.ts  # E2E accessibility tests
│   └── support/
│       └── commands.ts      # Custom Cypress commands
├── .eslintrc.cjs            # ESLint with jsx-a11y plugin
├── jest.config.js           # Jest configuration
├── cypress.config.ts        # Cypress configuration
└── package.json

Learning Topics

Strategy & Semantic Foundations

Topics covered:

  • Business case for accessibility (legal, market reach, SEO)
  • Shift-left methodology
  • Semantic HTML vs generic divs
  • Native button elements
  • .sr-only utility class for screen reader-only content

Implementation:

  • src/App.tsx:30-60 - Semantic landmarks
  • src/index.css:27-37 - .sr-only class
  • src/pages/FormsPage.tsx:130-140 - Native buttons

ARIA & Screen Readers

Topics covered:

  • Accessible name computation hierarchy
  • Accessibility tree structure
  • Screen reader interaction modes (Browse/Focus)
  • Native label elements vs span labels

Implementation:

  • src/pages/FormsPage.tsx:60-110 - Proper label associations
  • src/pages/FormsPage.tsx:72 - ARIA attributes

Focus Management

Topics covered:

  • Client-side routing focus management
  • Modal focus trap implementation
  • :focus-visible for keyboard-only focus indicators
  • Framework-specific accessibility considerations

Implementation:

  • src/App.tsx:17-40 - Route change focus management
  • src/components/Modal.tsx:15-100 - Focus trap
  • src/index.css:40-60 - Focus indicators

Testing & Processes

Topics covered:

  • ESLint with jsx-a11y plugin
  • Unit testing with jest-axe
  • E2E testing with cypress-axe
  • Accessibility personas and Definition of Done

Implementation:

  • .eslintrc.cjs - Linting configuration
  • src/components/Modal.test.tsx - Unit tests
  • cypress/e2e/accessibility.cy.ts - E2E tests
  • docs/definition-of-done.md - Process integration

Key Accessibility Patterns

Screen Reader-Only Content

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

Focus Management on Route Change

useEffect(() => {
  const heading = document.querySelector('h1')
  if (heading) {
    heading.setAttribute('tabindex', '-1')
    heading.focus()
    heading.addEventListener('blur', () => {
      heading.removeAttribute('tabindex')
    }, { once: true })
  }
}, [location.pathname])

Modal Focus Trap

// Trap Tab key within modal
const focusableElements = modalRef.current.querySelectorAll(
  'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
)
const first = focusableElements[0]
const last = focusableElements[focusableElements.length - 1]

if (e.shiftKey && document.activeElement === first) {
  e.preventDefault()
  last.focus()
} else if (!e.shiftKey && document.activeElement === last) {
  e.preventDefault()
  first.focus()
}

Testing

Automated Tests

Linting (ESLint + jsx-a11y):

npm run lint

Catches: Missing alt text, invalid ARIA, unlabeled inputs, div buttons

Unit Tests (Jest + jest-axe):

npm run test

Catches: Component-level ARIA issues, missing labels, incorrect roles

E2E Tests (Cypress + cypress-axe):

npm run test:e2e

Catches: Page-level issues, color contrast, focus management

Manual Testing

Keyboard Navigation:

  1. Press Tab to navigate through interactive elements
  2. Verify all elements are reachable
  3. Check focus indicators are visible
  4. Test modals trap focus correctly

Screen Reader Testing:

  • Windows: NVDA + Chrome/Firefox
  • macOS: VoiceOver + Safari
  • iOS: VoiceOver + Safari

Accessibility Checklist

Before considering a feature complete:

  • Linting passes (no jsx-a11y warnings)
  • Unit tests pass with jest-axe
  • E2E tests pass with cypress-axe
  • Manual keyboard testing completed
  • Screen reader tested
  • Color contrast verified (4.5:1 for text)
  • Focus indicators visible
  • All images have alt text
  • All form inputs have labels
  • Error messages announced

See docs/accessibility-checklist.md for complete checklist.

Browser/AT Compatibility

Tested with:

  • ✅ Chrome + NVDA (Windows)
  • ✅ Firefox + NVDA (Windows)
  • ✅ Safari + VoiceOver (macOS)
  • ✅ Safari + VoiceOver (iOS)
  • ✅ Edge + Narrator (Windows)

Common Accessibility Anti-Patterns to Avoid

  1. Div Buttons: Use <button> instead of <div onClick={...}>
  2. Span Labels: Use <label htmlFor="id"> instead of <span>
  3. Placeholder as Label: Always provide a proper label
  4. display:none on SR content: Use .sr-only pattern instead
  5. Auto-focus without user action: Only focus on user interaction
  6. Color-only information: Provide text or icon indicators too
  7. Positive tabindex: Use tabindex="-1" or "0" only

Resources

Official Documentation

Tools

Learning Materials

Contributing

This is a learning project demonstrating accessibility best practices. If you find accessibility issues or improvements:

  1. Check the accessibility checklist
  2. Run automated tests (npm run lint, npm run test, npm run test:e2e)
  3. Test with keyboard and screen reader
  4. Submit an issue or pull request

License

This project is created for educational purposes.

Acknowledgments

  • Enterprise Accessibility curriculum
  • WCAG 2.1 Working Group
  • axe-core and Deque Systems
  • React Testing Library and Cypress teams
  • WebAIM and The A11Y Project

Built with accessibility in mind from day one.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages