3.8 KiB
3.8 KiB
A11y: Color contrast (WCAG 2.2 AA)
This project uses theme tokens (see src/theme/app/Light.js / src/theme/app/Dark.js) as the single source of truth for core UI colors.
The goal is to ensure text and icons meet WCAG 2.2 AA contrast:
- Normal text: contrast ratio ≥ 4.5:1
- Large text / icons: contrast ratio ≥ 3:1
We intentionally enforce 4.5:1 for our key UI states (buttons, alert levels, banners/toasts), because:
- buttons mix text + icons, and size can vary with device scaling
- alert-level CTAs are primary critical actions
Approved core pairs (tokens)
All pairs below were validated with a standard WCAG contrast formula (relative luminance).
Buttons (react-native-paper)
Implementation notes:
- Contained buttons typically use
colors.primarybackground withcolors.onPrimarytext. - Outlined buttons in this codebase render with white background and primary-colored label (see
src/components/CustomButton.js).
| Usage | Foreground token | Background token | Target |
|---|---|---|---|
| Contained primary button label/icon | colors.onPrimary |
colors.primary |
≥ 4.5:1 |
| Outlined button label/icon (on white) | colors.primary |
colors.onPrimary |
≥ 4.5:1 |
| Disabled states (material defaults) | colors.onSurfaceDisabled |
colors.surfaceDisabled |
N/A (disabled content is excluded from contrast requirements) |
Alert levels (CTA backgrounds)
Alert level colors are under theme.custom.appColors.
These are used as:
- backgrounds for the “send alert” CTAs (text + icons), with
custom.appColors.onColoras the foreground - foreground indicators (dots/icons) on surfaces in places like notifications
| Alert level | Background token | Foreground token | Target |
|---|---|---|---|
| Red | custom.appColors.red |
custom.appColors.onColor |
≥ 4.5:1 |
| Yellow | custom.appColors.yellow |
custom.appColors.onColor |
≥ 4.5:1 |
| Green | custom.appColors.green |
custom.appColors.onColor |
≥ 4.5:1 |
| Unknown | custom.appColors.unknown |
custom.appColors.onColor |
≥ 4.5:1 |
| Call | custom.appColors.call |
custom.appColors.onColor |
≥ 4.5:1 |
Error / success / warning (banners + toasts)
This codebase uses a mix of:
colors.error+colors.onErrorwhen error is used as a backgroundcolors.ok,colors.no,colors.warnfor status backgrounds (e.g. confirmation/rejection)- toast “normal” uses
colors.surfaceVariantbackground withcolors.onSurfaceVarianttext (seesrc/lib/toast-notifications/toast.js)
| Usage | Foreground token | Background token | Target |
|---|---|---|---|
| Error background + white text | colors.onError |
colors.error |
≥ 4.5:1 |
| Success background + white text | colors.onPrimary |
colors.ok |
≥ 4.5:1 |
| Reject/Danger background + white text | colors.onPrimary |
colors.no |
≥ 4.5:1 |
| Warning background + white text | colors.onWarning |
colors.warn |
≥ 4.5:1 |
| Toast (normal) | colors.onSurfaceVariant |
colors.surfaceVariant |
≥ 4.5:1 |
Rationale for token adjustments
We keep component code unchanged and only adjust theme tokens.
Key changes (both Light/Dark) were made because the previous palette failed AA in multiple critical states:
- white on
error/no/criticalreds - white on
okgreens - white on alert-level colors (especially yellow/green/unknown)
- dark theme
primarywas too light for white text - light theme
onSurfaceVariantnarrowly missed 4.5:1 onsurfaceVariant
Branding impact was minimized by:
- preserving the overall hue families (blue primary, red/yellow/green alerts)
- applying the smallest darkening needed to cross AA thresholds