Accessibility Components Audit
Last updated: March 2026
Coverage Summary
| Check Category |
Tool |
Files |
Status |
| Colour contrast (WCAG AA) |
check-contrast.js |
src/ |
✅ CI enforced |
| ESLint a11y rules |
eslint-plugin-react-native-a11y |
src/ + app/ |
✅ CI enforced |
| Screen reader labels & roles |
Jest + @testing-library/react-native |
26 suites |
✅ CI enforced |
| Touch target sizing (44×44) |
check-touch-targets.js + Jest engine |
src/ + app/ |
✅ CI enforced |
Modal accessibilityViewIsModal |
Jest FocusOrder suite |
Modals |
✅ CI enforced |
| Focus order (button order) |
Jest FocusOrder suite |
Modals |
✅ CI enforced |
Component Catalog
UI Components — Full Coverage
| Component |
a11y File |
Engine |
Screen Reader |
Touch Target |
Focus/Modal |
Button |
Button.a11y.test.tsx |
✅ |
✅ |
✅ |
— |
Input |
Input.a11y.test.tsx |
✅ |
✅ |
— |
— |
Dropdown |
Dropdown.a11y.test.tsx |
✅ |
✅ |
— |
✅ |
ListItem |
ListItem.a11y.test.tsx |
✅ |
✅ |
✅ |
— |
FilterButton |
FilterButton.a11y.test.tsx |
✅ |
✅ |
✅ |
— |
CaseCard |
CaseCard.a11y.test.tsx |
✅ |
✅ |
— |
— |
CollapsibleSection |
CollapsibleSection.a11y.test.tsx |
✅ |
✅ |
— |
— |
ActionCard |
ActionCard.a11y.test.tsx |
✅ |
✅ |
— |
— |
ActionPill |
ActionPill.a11y.test.tsx |
✅ |
✅ |
— |
— |
ManageableListCard |
ManageableListCard.a11y.test.tsx |
✅ |
✅ |
✅ |
— |
NetworkStatusBanner |
NetworkStatusBanner.a11y.test.tsx |
✅ |
✅ (role=alert, live region) |
— |
— |
NotificationBell |
NotificationBell.a11y.test.tsx |
✅ |
✅ (dynamic label) |
— |
— |
EmptyState |
EmptyState.a11y.test.tsx |
✅ |
✅ |
— |
— |
StatusBadge |
StatusBadge.a11y.test.tsx |
✅ |
✅ |
— |
— |
SummaryCard |
SummaryCard.a11y.test.tsx |
✅ |
✅ |
— |
— |
IconButton |
IconButton.a11y.test.tsx |
✅ |
✅ |
✅ |
— |
FloatingActionButton |
FloatingActionButton.a11y.test.tsx |
✅ |
✅ |
✅ (56×56) |
— |
LogoutConfirmModal |
LogoutConfirmModal.a11y.test.tsx |
✅ |
✅ |
— |
✅ |
ForgotPasswordModal |
ForgotPasswordModal.a11y.test.tsx |
✅ |
✅ |
— |
✅ |
ConfirmNameDeleteModal |
ConfirmNameDeleteModal.a11y.test.tsx |
✅ |
✅ |
— |
✅ |
LocationUI |
LocationUI.a11y.test.tsx |
✅ |
— |
— |
— |
SearchBar |
SearchBar.a11y.test.tsx |
✅ |
— |
— |
— |
Header |
Header.a11y.test.tsx |
✅ |
— |
— |
— |
ExportScreen |
ExportScreen.a11y.test.tsx |
✅ |
— |
— |
— |
Dedicated Cross-Component Suites
| Suite File |
Coverage |
TouchTargets.a11y.test.tsx |
Button, FAB, FilterButton, ListItem, ManageableListCard |
FocusOrder.a11y.test.tsx |
LogoutConfirmModal, ForgotPasswordModal, ConfirmNameDeleteModal, Dropdown, multi-input forms |
Automation Scripts
| Script |
Purpose |
scripts/check-contrast.js |
WCAG AA 4.5:1 colour contrast scan → docs/fieldnotes_ai/color-contrast-report.md |
scripts/check-touch-targets.js |
WCAG 2.5.5 — scan inline styles for < 44px touch targets → docs/fieldnotes_ai/touch-targets-report.md |
scripts/accessibility-report.js |
Combined Jest + ESLint Markdown report → docs/fieldnotes_ai/accessibility-tests-report.md |
CI Pipeline — accessibility.yml
push/PR → main, sprint*
├─ eslint-a11y (ESLint Accessibility Static Analysis)
├─ contrast-checker (WCAG Color Contrast Check)
├─ jest-a11y (Jest Screen Reader and Focus Tests)
├─ touch-target-check (WCAG Touch Target Size Check)
└─ accessibility-report (Generate Combined Accessibility Report)
All jobs must pass for merge.
Engine Mock Rules (Phase 4)
The __mocks__/react-native-accessibility-engine.js mock enforces:
- Missing
accessibilityLabel — any interactive element without a label throws
- Missing
accessibilityRole — any element with onPress without a role throws
- Duplicate sibling labels — two siblings with the same label throws