Accessibility
Built-in accessibility modes for users with different needs, fully compliant with EU regulations.
EU Compliance Ready
User Accessibility Settings
These options are designed to be offered to end users. Preferences are automatically persisted to localStorage.
Uses Lexend, designed for improved readability
WCAG 1.4.12 compliant spacing
Adjusts status colors for better visibility
High-contrast 3px focus rings
Sample text to preview font and spacing changes.
EU Compliance
European Accessibility Act (EAA)
The European Accessibility Act (Directive 2019/882) requires digital products and services to be accessible to people with disabilities. Enforcement began June 28, 2025.
| Requirement | Standard | Status |
|---|---|---|
| Text contrast ratio | WCAG 1.4.3 (4.5:1) | Pass |
| UI component contrast | WCAG 1.4.11 (3:1) | Pass |
| Focus indicators visible | WCAG 2.4.7 | Pass |
| Text spacing adjustable | WCAG 1.4.12 | Pass |
| Keyboard accessible | WCAG 2.1.1 | Pass |
| Reduced motion support | WCAG 2.3.3 | Pass |
| Touch targets (mobile) | WCAG 2.5.8 (44px) | Pass |
| Windows High Contrast | forced-colors | Pass |
Automatic System Support
The design system automatically respects user system preferences:
- prefers-reduced-motion - All animations disabled when enabled
- prefers-contrast: more - Increased border contrast
- forced-colors - Windows High Contrast mode support
- Browser zoom - All sizes use rem units for proper scaling
Implementation
Use the useAccessibility hook to build settings interfaces:
import { useAccessibility } from "@sourceful-energy/ui"
function AccessibilitySettings() {
const {
fontMode, setFontMode,
colorMode, setColorMode,
spacingMode, setSpacingMode,
focusMode, setFocusMode,
} = useAccessibility()
return (
<div className="space-y-4">
{/* Dyslexia-friendly font */}
<Switch
checked={fontMode === "dyslexic"}
onCheckedChange={(v) => setFontMode(v ? "dyslexic" : "default")}
/>
{/* Color blind modes */}
<Select value={colorMode} onValueChange={setColorMode}>
<SelectItem value="default">Default colors</SelectItem>
<SelectItem value="deuteranopia">Red-green color blind</SelectItem>
<SelectItem value="protanopia">Red color blind</SelectItem>
<SelectItem value="tritanopia">Blue-yellow color blind</SelectItem>
<SelectItem value="achromatopsia">Grayscale</SelectItem>
</Select>
{/* Text spacing (WCAG 1.4.12) */}
<Switch
checked={spacingMode === "comfortable"}
onCheckedChange={(v) => setSpacingMode(v ? "comfortable" : "default")}
/>
{/* Enhanced focus (WCAG 2.4.7) */}
<Switch
checked={focusMode === "enhanced"}
onCheckedChange={(v) => setFocusMode(v ? "enhanced" : "default")}
/>
</div>
)
}Data Attributes
The provider sets these attributes on <html>:
| Attribute | Values | Purpose |
|---|---|---|
| data-font-mode | dyslexic | Switches to Lexend font |
| data-color-mode | deuteranopia, protanopia, tritanopia, achromatopsia | Color blind palettes |
| data-spacing | comfortable | WCAG 1.4.12 text spacing |
| data-focus-mode | enhanced | High-visibility focus rings |
Individual Hooks
For granular control, use individual hooks:
import {
useFontMode,
useColorMode,
useSpacingMode,
useFocusMode,
useDesignSystem,
} from "@sourceful-energy/ui"
// Individual settings
const { fontMode, setFontMode } = useFontMode()
const { colorMode, setColorMode } = useColorMode()
const { spacingMode, setSpacingMode } = useSpacingMode()
const { focusMode, setFocusMode } = useFocusMode()
// Full context (theme + all accessibility)
const ctx = useDesignSystem()Best Practices
Offer settings in your app
Add an accessibility settings panel using the hooks above. Users expect to find these in Settings or Profile pages.
Don't rely on color alone
Always combine color with icons or text labels for status indicators. Our Alert and Badge components support icons.
Test with keyboard navigation
All interactive elements should be reachable via Tab and operable with Enter/Space. Our Radix-based components handle this automatically.
Use semantic HTML
Use heading levels (h1-h6) correctly, label form inputs, and use landmark regions (main, nav, aside). Screen readers depend on semantic structure.