Accessibility
Every Aidash component ships with ARIA attributes, keyboard support, and focus management. This guide covers the invariants we test against and the patterns you should follow when composing components into screens.
Colour contrast
4.5:1 for body text, 3:1 for large text (18pt+ or 14pt bold). Below that, WCAG considers the text unreadable.
White on dark
15.3:1
Purple on dark
5.2:1
Gray on dark
2.1:1
Black on white
21:1
Light gray on white
2.3:1
Purple on white
9.6:1
Keyboard support
Every focusable element responds to a predictable set of keys.
| Key | Action |
|---|---|
| Tab | Move focus to the next element |
| Shift + Tab | Move focus to the previous element |
| Enter | Activate button, submit form, or open link |
| Space | Activate button or toggle a control |
| Esc | Close dialog, dropdown, or popover |
| ↑ ↓ ← → | Navigate within a group (menu, tab, radio) |
Focus rings
Aidash uses focus-visible so mouse users don't see a ring, keyboard users always do.
<button
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-(--ring) focus-visible:ring-offset-2"
>
Save
</button>--ring token defaults to the brand blue. Override once in your :root block to reskin every focus ring at once.Screen reader support
ARIA is a last resort — use semantic HTML first. When you must use ARIA, respect the standard patterns.
{/* Icon-only button — announce a label */}
<button aria-label="Delete item">
<TrashIcon />
</button>
{/* Loading — tell AT the state changed */}
<div role="status" aria-live="polite">
Saving your changes...
</div>
{/* Modal — announce the dialog, trap focus */}
<div role="dialog" aria-modal="true" aria-labelledby="title" aria-describedby="desc">
<h2 id="title">Confirm delete</h2>
<p id="desc">This action cannot be undone.</p>
</div>
{/* Form error — associate with the field */}
<input aria-invalid="true" aria-describedby="email-error" />
<p id="email-error" role="alert">Please enter a valid email.</p>Reduced motion
Some users get motion sickness from animations. Respect their preference.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}globals.css. Every animation in the library respects it automatically.Checklist
Tick each item before you ship. Click a box to remember what you've verified.