The Journal
Design Engineering/8 min read

Building Forms That Don't Make Users Want to Quit

Forms are where most users drop off. Here's how to build forms that are easy to fill out, validate properly, and actually feel good to use.

AJ

Why Forms Are So Hard to Get Right

Forms look simple. A few inputs, a button, done. But they're actually the hardest UI to build well. Validation, error states, loading states, accessibility, keyboard navigation, multi-step flows, responsive layout. Get any of these wrong and people leave. Here's how to get them right.

Structure First

form-structure.tsx

Validation That Helps

Bad validation yells at people. Good validation guides them:

  • Validate on blur, not on type. Don't show errors while someone is still typing.
  • Clear errors when they fix it. Remove the error as soon as the input becomes valid.
  • Say what's wrong AND how to fix it. Not "Invalid input." Instead: "Email must include @."
  • Mark required fields. Either mark required or optional. Not both. Most forms mark optional since most fields are required.
  • Use native validation when possible. type="email", required, pattern work great.
validation.tsx

Loading and Success States

submit-states.tsx

Accessibility Checklist

  • Every input has a visible <Label> linked with htmlFor
  • Error messages are linked to inputs with aria-describedby
  • Invalid inputs have aria-invalid="true"
  • Required fields are marked with aria-required="true"
  • Tab order follows visual order
  • Form can be submitted with Enter key
  • Focus moves to first error after failed submission

UX Tips

  • Single column. Multi-column forms are harder to scan. One column is almost always better.
  • Big enough inputs. Minimum height of 40px. 44px is better for touch.
  • Autofocus the first field. Save users a click.
  • Use the right input type. type="email" shows the @ keyboard on mobile. type="tel" shows the number pad.
  • Break long forms into steps. Show progress. Let people go back.
  • Save progress. If the form is long, save to localStorage so people don't lose their work.

The Short Version

  • Label every input. Use htmlFor. No exceptions.
  • Validate on blur, not on type. Clear errors when fixed.
  • Show what's wrong and how to fix it
  • Use React Hook Form + Zod for validation
  • Always show loading and success states on submit
  • Single column, big inputs, right input types
  • Break long forms into steps with saved progress
Newsletter

Get new posts in your inbox.

New templates, components, and essays on design engineering. Join 4,000+ developers — no spam, ever.