--- name: accessible-components description: Use when building or reviewing interactive UI that must meet WCAG 2.2 AA — focus management, ARIA roles and states, keyboard navigation, labels, and visible focus. Covers the accessibility mistakes agents make most. --- # Accessible Components ## Overview Accessibility is not a feature you add later — it's how you build interactive elements from the start. The single best move in a SaaS app is to **use real semantic elements and Radix/shadcn primitives**, which ship correct ARIA and keyboard behavior. Most a11y bugs come from re-inventing a button or dropdown with a `
`. ## When to use - Building any interactive control (menus, dialogs, tabs, toggles). - Reviewing UI for keyboard and screen-reader support. - A `
` is standing in for a button. ## Rule 1: Use the right element ```tsx // ✗ Inaccessible: no focus, no Enter/Space, no role
Save
// ✓ Accessible for free ``` A native ` ``` Decorative icons get `aria-hidden`; the control gets `aria-label`. ## Rule 3: Visible focus, always Never `outline-none` without a replacement. Use a focus ring on every interactive element: ```tsx className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" ``` `:focus-visible` shows the ring for keyboard users without flashing it on mouse clicks. ## Rule 4: Keyboard support - All actions reachable via Tab; logical order (don't fight the DOM with `tabindex` > 0). - `Esc` closes overlays; `Enter/Space` activate; arrow keys move within menus/tabs/radios. - Radix/shadcn primitives (`DropdownMenu`, `Dialog`, `Tabs`, `Select`) implement these — prefer them over hand-rolled widgets. ## Rule 5: Announce dynamic changes Screen readers miss silent DOM updates. Use live regions for async status: ```tsx

{saving ? "Saving…" : "All changes saved"}

``` Toasts should render in an `aria-live` region (sonner/shadcn handle this — see notifications-and-toasts). ## Quick checklist - [ ] Color contrast ≥ 4.5:1 for text (3:1 for large/UI). - [ ] Every control reachable and operable by keyboard. - [ ] Visible focus indicator on each control. - [ ] Inputs have associated labels; icon buttons have `aria-label`. - [ ] State conveyed beyond color alone (icon/text too). - [ ] Images have `alt`; decorative ones `alt=""`/`aria-hidden`. ## Pitfalls - **`
`** instead of `