WCAG 2.2 AA accessibility audit for export screens
epic-accounting-system-export-ui-task-009 — Perform a full WCAG 2.2 AA accessibility review of all four components in this epic: AccountingExportScreen, ExportDateRangePicker, ExportConfirmationDialog, and ExportHistoryPanel. Verify: colour contrast ratios ≥ 4.5:1 for normal text and ≥ 3:1 for large text; all interactive targets ≥ 44×44 dp; focus order matches visual order; all form fields have associated Semantics labels; dynamic content changes announce via live regions; modal dialogs trap focus and restore on dismiss. Fix all failures found during the audit and document the changes.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Start with the automated tap-target guidelines — they are the fastest to find and fix. Then manually walk each screen with VoiceOver enabled on a real iOS device (simulator VoiceOver is unreliable for focus-order testing). For focus trapping in ExportConfirmationDialog, wrap the dialog body in a FocusScope with a defined FocusNode and call FocusScope.of(context).requestFocus() on dialog open. Store the previously focused FocusNode before opening and restore it in the dialog's onDismiss callback.
For live region announcements, prefer SemanticsService.announce over rebuilding the widget tree — it is lower overhead and does not cause layout thrash. When adding Semantics labels to date fields, include the current value in the label string (e.g., 'Start date: 1 March 2026') so screen reader users hear the selected value without needing to activate the field. Reference WCAG 2.2 success criteria 1.4.3, 1.4.11, 2.4.3, 2.5.3, and 4.1.3 in the audit report.
Testing Requirements
Manual audit using VoiceOver on iOS 17+ and TalkBack on Android 12+ physical devices. Automated checks: add semantics golden tests using flutter_test's SemanticsController to assert label presence on key interactive widgets. Write at least one widget test per component that calls tester.getSemantics() and verifies label, hint, and enabled state. Run Flutter's built-in accessibility checks via AccessibilityGuideline (androidTapTargetGuideline and iOSTapTargetGuideline) in existing widget tests.
Document all manual test steps in the audit report so they can be re-run after future changes.
Export operations may take several seconds, and the UI must handle all intermediate states (loading, partial success, failure, duplicate warning) without leaving the coordinator on a blank or unresponsive screen. Missing state handling causes confusion and potentially double-submissions.
Mitigation & Contingency
Mitigation: Design the BLoC state machine with explicit states for each transition before writing any widget code: ExportIdle, ExportDuplicateWarning, ExportInProgress, ExportSuccess, ExportPartialSuccess, ExportFailed. Each state maps to a distinct UI. Widget tests cover all states.
Contingency: If a loading state is missed in production, surface a generic error state with a retry action rather than leaving the UI stuck. Add a timeout on the Edge Function call (default 30 seconds) that transitions to ExportFailed with a user-readable message.
The custom Export Date Range Picker may not be fully navigable with VoiceOver if the underlying Flutter date widgets do not expose the correct semantic tree. This is a critical accessibility failure for Blindeforbundet users who rely on screen readers.
Mitigation & Contingency
Mitigation: Use Flutter's built-in DateRangePicker as the base and wrap with explicit Semantics nodes for start and end labels. Test with VoiceOver on a physical iOS device as part of the definition of done for this component. Reference the existing AccessibilityTestHarness pattern used elsewhere in the app.
Contingency: If the custom picker fails accessibility audit, replace it with two independent DatePicker fields (start and end) using Flutter's standard accessible date input, which has broader VoiceOver support than range variants.