Egbe Lajo
GUIDELINE

Accessibility

WCAG AA guidelines built into every component. Color contrast, keyboard navigation, screen reader support, and touch targets.

Color Contrast

All text/background pairings meet WCAG AA minimum of 4.5:1:

PairingPreviewRatio
White / Primary textAa15.3:1
White / Secondary textAa7.7:1
Gray / Primary textAa14.8:1
Primary / WhiteAa5.2:1
Gold / Dark textAa5.8:1
Error / WhiteAa4.5:1

Keyboard Navigation

  • Focus rings: All interactive elements show ring-2 ring-primary/40 ring-offset-2 on :focus-visible
  • Tab order: Matches visual order (no custom tabIndex needed)
  • ESC to close: Modals and dropdowns close on Escape
  • Skip links: Add a skip-to-content link on navigation-heavy pages
// Focus ring is built into all components:
<button className="focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2">
  Action
</button>

Form Accessibility

  • Every Input has an associated <label> with htmlFor
  • Error messages use role="alert" for screen reader announcement
  • Inputs link to hints/errors via aria-describedby
  • Invalid inputs set aria-invalid="true"
// Built into the Input component:
<label htmlFor="email">E-mail</label>
<input
  id="email"
  aria-invalid={!!error}
  aria-describedby={error ? "email-error" : "email-hint"}
/>
{error && <p id="email-error" role="alert">{error}</p>}

Touch Targets (Mobile)

  • Minimum 44x44dp on all interactive elements (enforced via TOUCH_TARGET_MIN)
  • Hit slop: Small dismiss buttons use hitSlop=8
  • Press feedback: All touchable elements use Pressable with opacity 0.7

Screen Readers

  • accessibilityRole on all interactive RN components ("button", "checkbox", "radio")
  • accessibilityState for disabled, checked, selected, busy states
  • accessibilityLabel on icon-only buttons
  • aria-sort on sortable table headers (web)
  • aria-modal on dialog overlays (web)

Reduced Motion

The global CSS includes a prefers-reduced-motion media query that disables all animations and transitions for users who prefer reduced motion.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

On React Native, check AccessibilityInfo.isReduceMotionEnabled() before running layout animations.

Checklist

  • Color contrast: 4.5:1 minimum for all text
  • Focus rings visible on all interactive elements
  • Every form input has a <label>
  • Error messages announced via role="alert"
  • Tab order matches visual order
  • 44dp minimum touch targets on mobile
  • prefers-reduced-motion respected
  • No emojis as icons — SVG only