Quality
Accessibility
The bar every screen has to clear: contrast, keyboard, focus, motion, and meaning that never depends on color.
#The standard
Every text and background pairing meets WCAG 2.2 AA (4.5:1 for text) in light and dark. The full measured table is on Color, and this site’s build fails if a pairing falls below it.
#What to check on every screen
| Area | Requirement |
|---|---|
| Contrast | Use only the pairings in the contrast table. Re-check any new one, in both themes. |
| Not color alone | Status has words, an arrow, or a dot with a label. A delta’s direction is in its arrow. |
| Keyboard | Every control is reachable by Tab in reading order, and works with Enter or Space. No keyboard traps, except inside an open modal. |
| Focus | A visible 2px ring on every interactive element. Never remove it. |
| Names | Every input has a label tied by for/id. Icon-only buttons have aria-label. Icons are aria-hidden. |
| Structure | One h1 per page, headings in order, one nav landmark for the app, a main. |
| Charts | Sparklines have role="img" and an aria-label. The numbers are in text beside them. |
| Errors | role="alert", plain words, and focus stays where the person can act. |
| Motion | 120 to 200ms and only to confirm. prefers-reduced-motion is honored globally. |
| Zoom and reflow | Usable at 200% zoom and at 390px wide with no horizontal scroll. |
| Targets | Buttons and inputs are at least 40px tall. |
#Patterns that work
#Label and hint
We send your weekly pack here.
Code
<div class="field">
<label for="a11y-email">Email</label>
<input id="a11y-email" type="email" aria-describedby="a11y-hint" autocomplete="email" />
<div class="field-hint" id="a11y-hint">We send your weekly pack here.</div>
</div>
#Status that does not rely on color
● ConnectedWaiting for first reportFailed
Code
<div class="btn-row"><span class="pill pill-accent">● Connected</span><span class="pill pill-warn">Waiting for first report</span><span class="pill pill-danger">Failed</span></div>
#Dialog
- Use
role="dialog"andaria-modal="true"with an accessible name from its heading. - Move focus into the dialog on open. Return it to the trigger on close. Escape closes it.
#How to test
- Tab through it with no mouse. Can you do everything, and always see where you are?
- Flip the theme using the toggle in this guide’s top bar, or the Light and Dark buttons on any specimen.
- Squint test: view in grayscale. Is every status still readable?
- Phone width: 390px, no horizontal scroll.
- Screen reader: headings and landmarks read in a sensible order, and every control has a name.
- Reduced motion: turn it on in your OS. Nothing should depend on animation.