How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/param087/saas-ui-skills --skill accessible-componentsBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
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 <div>.
When to use
- Building any interactive control (menus, dialogs, tabs, toggles).
- Reviewing UI for keyboard and screen-reader support.
- A
<div onClick>is standing in for a button.
Rule 1: Use the right element
// ✗ Inaccessible: no focus, no Enter/Space, no role
<div onClick={save} className="btn">Save</div>
// ✓ Accessible for free
<button type="button" onClick={save} className="btn">Save</button>A native <button> is focusable, fires on Enter/Space, and announces as a button. Same for <a> (navigation), <label> (form association), <nav>/<main>/<header> (landmarks).
Rule 2: Every input has a label
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" />
// Icon-only buttons need an accessible name:
<Button size="icon" aria-label="Close">
<X className="h-4 w-4" aria-hidden />
</Button>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:
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). Esccloses overlays;Enter/Spaceactivate; 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:
<p role="status" aria-live="polite">{saving ? "Saving…" : "All changes saved"}</p>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 onesalt=""/aria-hidden.
Pitfalls
- `<div onClick>` instead of
<button>— no keyboard, no role. - `outline-none` with no focus replacement — keyboard users get lost.
- Placeholder as label — disappears on input, fails screen readers.
- Color-only state (red border, no message) fails colorblind users.
- Hand-rolled dropdowns/modals missing focus trap and arrow keys — use primitives.
Hand-off
The accessibility baseline every other skill assumes — forms-and-validation, modals-and-dialogs, and navigation-patterns all build on these rules.




