Files
aragrp/docs/design-system/accessibility.md
T

88 lines
2.7 KiB
Markdown
Raw Normal View History

# Accessibility
Accessibility is priority #1 in the design system hierarchy. Visual polish never overrides perceivable, operable UI.
## Color contrast
- Body text (`foreground` on `background`) and muted text must remain readable in both themes.
- Do not place `muted-foreground` on muted backgrounds without checking contrast.
- Primary buttons use white label on `#29a19c`—do not lower primary opacity on labels.
- Never convey meaning by color alone (pair with text/icon).
## Focus ring
Visible focus is mandatory for keyboard users.
| Control | Pattern |
| --- | --- |
| Button | `focus-visible:ring-[3px] focus-visible:ring-ring/40 focus-visible:border-ring` |
| Input | `focus-visible:ring-[3px] focus-visible:ring-primary/25 focus-visible:border-primary` |
| Generic | Prefer ring tokens; never `outline-none` without replacement |
Do not remove focus styles from cards/links that are interactive.
## Keyboard navigation
- All buttons, links, and controls reachable via Tab.
- Menus / sheets / dialogs use Radix primitives (focus trap + Escape).
- Maintain logical RTL tab order; avoid positive `tabIndex` except when necessary.
- Icon-only controls need accessible names.
## ARIA expectations
| Case | Requirement |
| --- | --- |
| Icon button | `aria-label` |
| Decorative icon/image | `aria-hidden` / empty `alt` |
| Expandable | `aria-expanded` + controls id |
| Dialogs / sheets | Titled (`SheetTitle`, `DialogTitle`) — `sr-only` if visually hidden |
| Invalid fields | `aria-invalid` + error text |
| Landmark nav | `aria-label` on primary `<nav>` |
| Decorative sections | `aria-hidden` on `.section-decor` |
Prefer native semantics (`button`, `a`, `label`) before ARIA.
## Reduced motion
- Honor `prefers-reduced-motion`.
- `MotionReveal` already disables motion.
- New CSS animations need a reduced-motion override.
- Do not autoplay motion-critical content.
## Touch targets
| Control | Minimum |
| --- | --- |
| Default button | 40×40 (`h-10`) |
| Large button | 48×48 |
| Icon button | 40×40 |
| Compact button | 32×32 — avoid for primary mobile actions |
| Input | ≥ 36px height (`h-9`); 48px when paired with lg submit |
## Forms
- Visible labels (not placeholder-only).
- Error text associated with fields.
- Preserve browser autofill / zoom-safe 16px text on mobile inputs.
## Images & media
- Meaningful `alt`.
- Do not flash high-contrast animations.
## Checklist snippet
- [ ] Keyboard only can complete the flow
- [ ] Focus visible on all interactive elements
- [ ] Contrast OK in light and dark
- [ ] Reduced motion OK
- [ ] SR labels on icon buttons
- [ ] No keyboard trap outside modals
## Related
- [forms.md](./forms.md)
- [motion.md](./motion.md)
- [dark-mode.md](./dark-mode.md)
- Cursor rule: `.cursor/rules/accessibility.mdc`