high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

The toggle button renders as a suffixIcon inside InputDecoration and is correctly positioned within AppTextField
Touch target is at minimum 48x48 logical pixels as required by WCAG 2.2 Success Criterion 2.5.8 (Target Size)
When password is hidden, the icon is visibility_off and the Semantics label reads 'Show password'
When password is visible, the icon is visibility and the Semantics label reads 'Hide password'
Tapping the toggle switches obscureText on the associated TextField between true and false
The Semantics widget includes both label and hint properties so VoiceOver and TalkBack announce the action correctly
The widget is stateless — it accepts an isVisible bool and an onToggle VoidCallback, delegating state to the parent
The icon colour meets WCAG 2.2 AA non-text contrast ratio of ≥3:1 against the input field background in both light and dark design token themes
Widget renders correctly in golden tests at 1x, 2x, and 3x pixel density
The widget is exported from the shared widgets library and documented with a brief dartdoc comment

Technical Requirements

frameworks
Flutter
flutter_test
performance requirements
Widget build must not trigger any async operations
State toggle must complete within a single frame (no animation delay required unless specified by design)
security requirements
The obscureText state must not be persisted to any storage — it is ephemeral UI state only
The widget must not expose the password value in any accessibility tree attribute other than the TextField's own value
ui components
PasswordVisibilityToggle
AppTextField (parent, modified to accept toggle)
Semantics
IconButton
Icon (visibility / visibility_off)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implement as a stateless widget with signature: PasswordVisibilityToggle({required bool isVisible, required VoidCallback onToggle}). Wrap IconButton in a SizedBox with width and height of 48 to guarantee touch target size — do not rely on the theme's default IconButton splash radius alone. Use Semantics with label and button: true properties wrapping the IconButton. Pull icon colours from the design token system (e.g., AppColors.iconSecondary) rather than hardcoding hex values, so the widget automatically adapts to organisation theming.

This widget is part of the shared widget library used across all three organisations (NHF, Blindeforbundet, HLF) so accessibility requirements are non-negotiable.

Testing Requirements

Widget tests using flutter_test: verify initial state renders visibility_off icon and Semantics label 'Show password'; verify tap produces visibility icon and label 'Hide password'; verify tap again restores initial state; verify touch target size is ≥48x48 via tester.getSize(). Accessibility test: use flutter_test's SemanticsController to assert that the node has the correct label and is focusable. Golden test for visual regression at standard density. All tests must pass without platform channels.

Component
Password Visibility Toggle
ui low
Epic Risks (3)
high impact medium prob scope

Automated accessibility checks (e.g., flutter_accessibility_service) may pass while manual VoiceOver/TalkBack testing reveals focus-order issues, missing semantic roles, or live region announcements that fire too early or not at all. Discovering these late risks delaying the MVP release.

Mitigation & Contingency

Mitigation: Conduct manual VoiceOver and TalkBack testing on physical devices at the end of every sprint, not only at release. Define accessibility acceptance criteria per component and include them in the DoD. Use Semantics widgets explicitly rather than relying on implicit semantics from Flutter's default widgets for all interactive elements.

Contingency: Maintain a prioritized accessibility bug backlog separate from the main backlog. If critical VoiceOver issues are found close to release, create an explicit accessibility hotfix sprint before TestFlight distribution to Blindeforbundet testers.

medium impact medium prob technical

Keyboard height varies significantly between iOS and Android, between device sizes (iPhone SE vs iPad), and with third-party keyboards. The KeyboardAwareLayout may not correctly adjust scroll offset in all combinations, causing input fields to remain hidden behind the keyboard on certain device/keyboard configurations.

Mitigation & Contingency

Mitigation: Test on a matrix of devices including iPhone SE (small viewport), a mid-size Android phone, and a tablet. Implement the layout using MediaQuery.viewInsets.bottom rather than a fixed padding value to correctly respond to any keyboard height. Include edge cases for floating keyboards on iPads.

Contingency: If device-specific issues are found after release, implement a bottom-padding fallback using BottomPadding inset and allow users to manually scroll. Log affected device/OS combinations for targeted fixes.

high impact low prob dependency

If the design token system's colour palette is updated without re-running contrast validation, form field labels, error messages, or placeholder text could fall below the WCAG 2.2 AA 4.5:1 ratio, causing a compliance regression.

Mitigation & Contingency

Mitigation: Integrate a contrast ratio validator (e.g., a CI lint step using the contrast-ratio-validator component) that checks all colour pairs used in the login form on every pull request. Document which token pairs are used for labels, errors, and backgrounds in the login form.

Contingency: If a contrast regression is detected post-merge, hot-patch the affected design token value. Do not ship a TestFlight build with known WCAG AA failures to Blindeforbundet testers.