Accessibility

TetrisUI is built on Radix UI primitives, which handle the hard parts of accessibility: focus trapping, keyboard interaction, ARIA attributes, and screen reader announcements. This page documents what you get for free and what you need to do as a consumer.

Built-in Behaviors

Keyboard Navigation

Every interactive component is fully operable with keyboard alone. Tab to move focus, Enter/Space to activate, Arrow keys for within-component navigation, Escape to dismiss overlays.

Components: Dialog, Sheet, Select, DropdownMenu, Tabs, Accordion, Command, Combobox

Focus Management

Overlays trap focus when open. Focus returns to the trigger when dismissed. Focus rings are visible and use the --ds-ring token (customizable via theme).

Components: Dialog, AlertDialog, Sheet, Popover, Command

Screen Reader Support

All components use correct ARIA roles, states, and properties via Radix primitives. Labels are associated with inputs. Live regions announce dynamic content changes.

Components: All form components, Alert, Toast, Progress

Color Contrast

Text colors meet WCAG 2.1 AA contrast ratios (4.5:1 for normal text, 3:1 for large text). Semantic colors (success, warning, error) are never the sole indicator; always paired with text or icons.

Components: Badge, Alert, Progress, all text styles

Motion & Animation

All animations respect prefers-reduced-motion. Overlay transitions are short (200-300ms). No infinite animations except loading spinners.

Components: Dialog, Sheet, Popover, Accordion, Spinner

Patterns to Follow

Forms

Label every input

<Label htmlFor="email">Email</Label>
<Input id="email" />

Announce errors

<Input error="Required" aria-invalid="true" />

Group related controls

<RadioGroup aria-label="Accounting system">
  <RadioGroupItem value="qb" />
</RadioGroup>

Overlays

Always add titles

<DialogTitle>Confirm sync</DialogTitle>
<DialogDescription>This will sync all orders.</DialogDescription>

Use AlertDialog for destructive actions

<AlertDialog> (requires explicit Cancel/Confirm)

Tooltip for icon-only buttons

<Tooltip><TooltipTrigger asChild>
  <Button size="icon"><Icon /></Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent></Tooltip>

Navigation

Breadcrumbs use nav + aria-label

<Breadcrumb> (renders <nav aria-label="breadcrumb">)

Skip to content link

<a href="#main" className="sr-only focus:not-sr-only">Skip to content</a>

Current page indicator

<BreadcrumbPage> (sets aria-current="page")

Testing Checklist

Tab through every interactive element on the page
Activate every control with Enter and Space
Navigate within compound components with Arrow keys
Dismiss overlays with Escape
Verify focus returns to trigger after overlay closes
Run axe-core or Lighthouse accessibility audit
Test with VoiceOver (macOS) or NVDA (Windows)
Verify at 200% browser zoom
Check with prefers-reduced-motion enabled

Resources

Radix Accessibility

How Radix primitives handle a11y

WAI-ARIA Practices

W3C design pattern reference

axe-core

Automated accessibility testing

WCAG 2.1 Quick Ref

Success criteria checklist