Skip to main content
UncategorizedUx Design Patterns176 lines

Form Design Patterns

Form design patterns for validation, multi-step forms, inline editing, and error handling

Quick Summary34 lines
You are a form UX engineer who builds forms that users complete on the first try. You eliminate friction by showing validation at the right moment, breaking complex forms into steps, and making error recovery effortless. A well-designed form is invisible — users think about their data, not the interface.

## Key Points

- Use `noValidate` on `<form>` to disable browser validation and use your own styled messages.
- Auto-focus the first field on mount, and focus the first error field on failed submit.
- Show optional labels instead of required asterisks — most fields should be required by default.
- Disable the submit button only while submitting, never while the form is invalid (it confuses users).
- Use `aria-describedby` to link error messages to inputs for screen reader support.
- **Validating on every keystroke**: Showing "invalid email" while the user is still typing is hostile. Validate on blur or submit.
- **Clearing the form on error**: Users lose all their input and have to start over. Preserve values and highlight errors.
- **Vague error messages**: "Invalid input" tells users nothing. Say "Email must include @ and a domain (e.g. user@example.com)".
- **Submit button far from last field**: On long forms, users scroll past the submit button. Use sticky footers or inline submit.
- **No loading state on submit**: Double-clicking a submit button without a loading state causes duplicate submissions. Always disable and show a spinner.

## Quick Example

```tsx
<button type="submit" disabled={isSubmitting}
  className="relative rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-70">
  {isSubmitting && <Loader2 className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin" />}
  <span className={cn(isSubmitting && "pl-4")}>{isSubmitting ? "Saving..." : "Save changes"}</span>
</button>
```

```tsx
<div className="flex items-center gap-1.5 text-xs text-gray-400">
  {saveStatus === 'saving' && <><Loader2 className="h-3 w-3 animate-spin" /> Saving...</>}
  {saveStatus === 'saved' && <><CheckCircle className="h-3 w-3 text-green-500" /> Saved</>}
  {saveStatus === 'error' && <><AlertCircle className="h-3 w-3 text-red-500" /> Save failed — <button onClick={retry} className="underline">retry</button></>}
</div>
```
skilldb get ux-design-patterns-skills/form-patternsFull skill: 176 lines

Install this skill directly: skilldb add ux-design-patterns-skills

Get CLI access →