Skip to content

Latest commit

 

History

History
96 lines (69 loc) · 5.09 KB

ACCESSIBILITY.md

File metadata and controls

96 lines (69 loc) · 5.09 KB

Accessibility — Thingstead+

Conformance Target

WCAG 2.1 Level AA — satisfying US Federal Section 508 (Revised 2018) and State of Oregon digital accessibility requirements.

Testing Approach

Automated

Tool Scope How to Run
eslint-plugin-jsx-a11y Static JSX analysis (missing labels, invalid ARIA, click-without-keyboard) npx eslint .
vitest-axe Runtime axe-core scans of rendered component trees npx vitest run (a11y tests in src/test/a11y.test.jsx)

Automated tools catch approximately 30-50% of WCAG issues. Manual testing is required for the remainder.

Manual

  • Keyboard-only navigation: Tab through every view without a mouse. All interactive elements must be reachable and operable.
  • Screen reader verification: Test with VoiceOver (macOS) or NVDA (Windows). Modals must announce title and description. Live regions must announce notices and search results.
  • Zoom/reflow: Verify content at 200% text zoom and 320px viewport width.
  • Color contrast: Verify all text/background combinations meet 4.5:1 (normal text) or 3:1 (large text, UI components).

Keyboard Navigation

Key Action
Tab / Shift+Tab Move between interactive elements
← / → Navigate between phase tabs
Escape Close any open modal
Ctrl/Cmd+Z Undo
Ctrl/Cmd+Shift+Z Redo
? Open keyboard shortcuts reference
Enter Submit forms, activate buttons

Focus Management

  • Skip link: Hidden link appears on first Tab press — jumps to main content area.
  • Focus trap: Modals trap focus within the dialog until closed. Focus returns to the trigger element on close.
  • Focus visible: All interactive elements show a 2px solid outline on :focus-visible.

Color and Contrast

  • Dark theme: Primary text #e8e5dc on background #0f0f0f — contrast ratio ~18:1 (AAA).
  • Disabled elements: Text #b0b0b0 on #1a1a1a — contrast ratio ~5.5:1 (AA).
  • Status indicators: All color-coded badges include text labels. Color is never the sole means of conveying information.
  • Focus ring: #e8e5dc outline — visible against all background colors.

Reduced Motion

The application respects prefers-reduced-motion: reduce:

  • All CSS animations are suppressed (duration set to 0.01ms).
  • Framer Motion animations are disabled via useReducedMotion().
  • Hover transforms are removed.

Semantic Structure

  • Landmarks: <main>, <nav> (sidebar), skip link to main content.
  • Headings: Single <h1> per view. Logical heading hierarchy within phase/artifact content.
  • Forms: Related controls wrapped in <fieldset> with <legend> (visually hidden where appropriate).
  • Tables: All data tables include <caption> (sr-only), <th scope="col">, and proper <thead>/<tbody> structure.
  • Modals: role="dialog", aria-modal="true", aria-labelledby (title), aria-describedby (body).
  • Tabs: Phase navigation uses role="tablist" → role="tab" with aria-selected, aria-controls, and arrow key navigation.
  • Live regions: Notices use aria-live="assertive". Search results use aria-live="polite".

Known Limitations

  1. Dashboard widget drag-and-drop: Layout rearrangement via react-grid-layout is mouse-only. All widget content remains keyboard accessible. Widgets are marked as role="region" with aria-label for screen reader orientation.

  2. Markdown editor: The toolbar buttons for bold/italic/link formatting are keyboard accessible, but the live preview does not announce changes to screen readers in real-time.

  3. Color contrast in phase badges: Phase-specific background colors (defined per plan template) may not all meet 3:1 non-text contrast against adjacent surfaces. Badge text always meets 4.5:1.

WCAG 2.1 AA Success Criteria Coverage

Category Criteria Covered Notes
Perceivable (1.x) 1.1.1, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.4.1, 1.4.3, 1.4.4, 1.4.10, 1.4.11, 1.4.12, 1.4.13 Text alternatives, structure, contrast, reflow
Operable (2.x) 2.1.1, 2.1.2, 2.1.4, 2.4.1, 2.4.2, 2.4.3, 2.4.5, 2.4.6, 2.4.7 Keyboard, skip link, focus, titles
Understandable (3.x) 3.1.1, 3.2.1, 3.2.3, 3.2.4, 3.3.1, 3.3.2, 3.3.3, 3.3.4 Language, consistency, errors
Robust (4.x) 4.1.2, 4.1.3 Name/role/value, status messages

How to Contribute Accessibly

When adding new components:

  1. Use semantic HTML (<button>, <a>, <input>, <table>) over <div> with click handlers.
  2. All interactive elements must be keyboard accessible (Tab + Enter/Space).
  3. Icon-only buttons require aria-label.
  4. Form groups require <fieldset className="a11y-group"> with <legend>.
  5. Data tables require <caption className="sr-only"> and scope="col" on headers.
  6. Modals require role="dialog", aria-modal="true", aria-labelledby, aria-describedby.
  7. Dynamic content changes require aria-live regions.
  8. Run npx eslint . before committing — jsx-a11y rules will catch common issues.
  9. Add axe scans for new major components in src/test/a11y.test.jsx.