Accessibility (A11y)
Ensure UI is operable and understandable for users with assistive technologies.
Recommended approach
- Build on accessible primitives (Base UI, Radix UI, or React Aria).
- Validate keyboard navigation and focus order for every critical flow.
- Run automated checks plus manual screen-reader passes on key journeys.
Alternatives and when to choose them
- Strict WCAG process for regulated domains.
- Baseline accessibility checks for internal-only tools.
Implementation checklist
- Add semantic landmarks and heading hierarchy.
- Verify visible focus styles.
- Test dialogs, menus, and forms with keyboard only.
Practical examples
Icon-only button with an accessible name
<button type="button" aria-label="Open settings" className="p-2 rounded-md">
<SettingsIcon aria-hidden="true" />
</button>Form field with explicit label and error announcement
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-invalid={Boolean(error)}
aria-describedby={error ? "email-error" : undefined}
/>
{error ? (
<p id="email-error" role="alert">
{error}
</p>
) : null}Dialog with initial focus target
<Dialog>
<DialogTrigger asChild>
<button type="button">Delete project</button>
</DialogTrigger>
<DialogContent>
<DialogTitle>Delete project?</DialogTitle>
<p>This action cannot be undone.</p>
<button autoFocus type="button">
Cancel
</button>
<button type="button">Delete</button>
</DialogContent>
</Dialog>Status updates that screen readers can hear
<p aria-live="polite">{isSaving ? "Saving changes..." : "Changes saved."}</p>Common pitfalls
- Using visual-only state indicators.
- Missing accessible names on icon-only controls.