# Form error messages are inline and descriptive

- **Pattern:** `ab-001754` (`marketing-conversion.form-optimization.form-error-feedback`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001754
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001754)

## Why it matters

A top-of-form banner saying "There was an error" forces visitors to re-scan every field to find what went wrong, and many simply abandon instead. Inline errors rendered directly under the offending field tell the visitor exactly what to fix and where — a fundamental usability affordance that is also a WCAG 2.2 SC 3.3.1 (Error Identification) requirement for accessible form validation, meaning the absence of inline errors creates both a conversion drag and a compliance gap.

## Severity rationale

Medium because non-inline error feedback increases abandonment and fails WCAG 2.2 SC 3.3.1 but does not block submission outright.

## Remediation

Render validation errors inline, adjacent to the specific field that caused them, with a descriptive message ("Email address is invalid") rather than a generic toast. Adopt `react-hook-form` with `zod` resolvers and the shadcn `Form` primitives in `components/ui/form.tsx`:

```tsx
<FormField
  name="email"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <FormControl>
        <Input {...field} />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>
```

## Detection

- **ID:** `form-error-feedback`
- **Severity:** `medium`
- **What to look for:** Examine form components for error handling patterns. Check: (1) Where error messages appear — are they inline (adjacent to the specific field that errored) or only as a banner/toast at the top of the form? (2) Are error messages descriptive ("Email address is invalid" or "Password must be at least 8 characters") versus generic ("There was an error" or "Please fix the errors above")? (3) Check for use of client-side form validation libraries (react-hook-form, formik, zod with form integration) which typically implement inline error patterns. Look at the form component's error rendering JSX.
- **Pass criteria:** Count all form components with validation and check each for inline error display. Form components render error messages inline — adjacent to the specific field that caused the error. At least 80% of forms must display field-level errors. Report the ratio: "X of Y forms display inline field-level errors."
- **Cross-reference:** For inline validation timing (blur/change vs. submit-only), see the inline-validation check in this audit.
- **Fail criteria:** All errors, including field-level validation errors, display only as a banner at the top of the form with no inline field-level error messages. OR error messages are generic ("An error occurred") for all scenarios.
- **Skip (N/A) when:** No forms found in the marketing or conversion pages.
- **Detail on fail:** Describe the error rendering pattern found. Example: `"SignupForm component renders a single error toast on submit failure — no inline field-level error messages. Email validation error reads 'Please check your inputs' without specifying which field."`.
- **Remediation:** Inline error messages tell users exactly what to fix and where. A top-banner error makes users re-scan the form to find the problem.

  With react-hook-form and zod:

  ```tsx
  <FormField
    name="email"
    render={({ field, fieldState }) => (
      <FormItem>
        <FormLabel>Email</FormLabel>
        <FormControl>
          <Input {...field} />
        </FormControl>
        {/* Inline error message */}
        <FormMessage />  {/* Renders fieldState.error.message */}
      </FormItem>
    )}
  />
  ```

## External references

- wcag 3.3.1

Taxons: user-experience

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