# Onboarding UI is accessible to users with disabilities

- **Pattern:** `ab-002372` (`saas-onboarding.onboarding-ux.accessibility-of-onboarding`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002372
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002372)

## Why it matters

Inaccessible signup and onboarding flows violate WCAG 2.2 SC 1.3.1 (Info and Relationships), 2.1.1 (Keyboard), 2.4.3 (Focus Order), 2.4.11 (Focus Not Obscured), and Section 508 §502.3 — and expose the company to ADA Title III litigation risk in the US. Form fields without labels are unusable with a screen reader; missing `role="alert"` means error messages are invisible to assistive technology. These aren't cosmetic gaps: they legally and functionally exclude users with disabilities from your product at the first interaction.

## Severity rationale

Critical because inaccessible onboarding is both a legal exposure under ADA/Section 508 and a hard blocker for users who rely on screen readers or keyboard navigation to complete signup.

## Remediation

In `src/app/(auth)/signup/page.tsx`, associate every input with a visible label and link errors via `aria-describedby`:

```tsx
<div>
  <Label htmlFor="email">Email</Label>
  <Input
    id="email"
    type="email"
    aria-describedby={emailError ? "email-error" : undefined}
  />
  {emailError && (
    <p id="email-error" role="alert" className="text-destructive text-sm">
      {emailError}
    </p>
  )}
</div>
```

Audit every `outline: none` in your global CSS — either remove it or add a visible `:focus-visible` replacement. For modal dialogs, use a focus trap library (`focus-trap-react`) so keyboard users can't tab outside the dialog.

## Detection

- **ID:** `accessibility-of-onboarding`
- **Severity:** `critical`
- **What to look for:** Count all form fields in signup and onboarding. For each, classify whether it has an associated `<label>` or `aria-label`. Count error messages and check for `aria-describedby` or `role="alert"`. Enumerate interactive elements and verify keyboard navigability. Check focus management in modals. Count `outline: none` usages.
- **Pass criteria:** 100% of form fields in signup have an associated `<label>` or `aria-label`. Error messages use `aria-describedby` or `role="alert"`. All interactive elements are reachable via keyboard. No `outline: none` without a visible focus replacement. Report even on pass: "Checked N form fields — all have labels. N error states use role=alert."
- **Fail criteria:** Any of: form fields without labels or `aria-label`; error messages that only appear visually with no `role="alert"`; interactive elements not reachable by keyboard; focus not trapped in modal dialogs; focus indicators removed with `outline: none` and no visible replacement.
- **Skip (N/A) when:** The project has no user-facing UI (API-only, CLI tool, or library).
- **Detail on fail:** List specific failures. Example: `"Signup form: email and password fields have no associated <label>. Error messages have no role='alert'. Modal dialog does not trap focus. Tab order skips the 'Show password' toggle."`
- **Remediation:** In your signup form at `src/app/(auth)/signup/page.tsx`:

  ```tsx
  <div>
    <Label htmlFor="email">Email</Label>
    <Input id="email" type="email" aria-describedby={error ? "email-error" : undefined} />
    {error && <p id="email-error" role="alert" className="text-destructive text-sm">{error}</p>}
  </div>
  ```
- **Cross-reference:** For a comprehensive accessibility review across the full application, the Accessibility Fundamentals Audit covers WCAG 2.1 AA compliance in depth.

---

## External references

- wcag 1.3.1
- wcag 2.1.1
- wcag 2.4.3
- wcag 2.4.11
- section-508 502.3

Taxons: accessibility

HTML version: https://auditbuffet.com/patterns/ab-002372
