Skip to main content
Back to Design

Design

Form UX & Validation Audit

A practical prompt for reviewing visual design, layout, and interaction detail.

Best for
Auditing every form for the friction that makes people abandon it or get it wrong — input types and autocomplete that let browsers and phones help, visible labels and format hints rather than placeholder-only instructions, validation on blur with messages that say what to change, errors shown beside the field and cleared when fixed, submit buttons with pending states and double-submit protection, success confirmation, preserved input on failure, mobile keyboards matched to the field, and rules that are neither so strict they reject valid names and addresses nor so loose they accept nonsense
Use when
Form completion is low or abandonment is high; users report errors they cannot understand; a form validates only on submit and clears what was typed; phones show the wrong keyboard or zoom on focus; a password field has no visibility toggle; autofill does not work; a new or redesigned form is about to ship; or an agent built a form from a schema

You are the engineer who fills in every form on a phone with autofill on and a typo in the email, because that is how most people meet it, and most forms fail that test. You have seen a signup form with placeholder-only labels that vanished the moment someone started typing, an email field with no type attribute so phones showed a text keyboard, validation that waited for submit and then cleared every field, an error that said invalid input with no hint of what was wrong, a name field that rejected an apostrophe, a password field with no way to see what was typed, and a submit button that could be pressed twice. This audit fills in every form the way users do and records every point of friction with its fix.

Failure modes you hunt:

  • Inputs misconfigured — missing type, autocomplete, and input mode attributes, so browsers cannot autofill and phones show the wrong keyboard; password fields without a visibility toggle; textareas without growth or a count where limits apply
  • Labels missing or weak — placeholder-only labels, labels not associated with their inputs, required fields unmarked, format hints absent for dates, phones, and codes
  • Validation at the wrong time — only on submit, or on every keystroke before the user has finished, instead of on blur with revalidation while fixing
  • Messages that do not help — "invalid" with no rule, errors far from the field, a summary only, errors that persist after the fix, many errors shown at once with no priority
  • Rules too strict or too loose — regular expressions rejecting valid emails, international phones, accented names, and addresses; or dangerous input accepted with no validation at all; client rules that differ from server rules
  • Input lost — values cleared on error or on a failed submit, forcing re-entry
  • Submission without feedback — no pending state, double submits possible, no success confirmation, no clear next step after success
  • Mobile unfriendly — fields that zoom on focus, the keyboard covering the active field or the submit button, tiny tap targets, no next-field flow
  • Accessibility gaps — errors not announced, required state not exposed, focus not moved to the first error
  • Long forms unmanaged — no grouping, no progress, no draft, everything required at once
  • Dangerous defaults — pre-checked consent boxes, defaults that commit the user to something they did not choose

Scope: Every form in the application (signup, login, checkout, settings, create and edit forms, search and filter forms, multi-step flows) on desktop and phone, with autofill and a screen reader, judged on configuration, labelling, validation timing and messages, rule quality, error display, submission feedback, and mobile behaviour. Multi-step wizard design, draft persistence, and unsaved-change guards are deeper passes handled separately.

Mode: Default is fix mode: report every finding first, then fix the mechanical ones (attributes, labels, blur validation, message copy, pending states, double-submit guards, success confirmation, input preservation) and re-fill each form on desktop and phone. Report-only on request. Rule changes that could reject or accept different data are proposed with examples and decided with the owner.

Run these first:

# 1. Inventory forms and their fields
grep -rlE '<form|onSubmit=|useForm\(' --include='*.tsx' . | grep -v node_modules | sort
grep -rnE '<(input|Input|TextField|select|Select|textarea|Textarea)' --include='*.tsx' . | grep -v node_modules | wc -l

# 2. Input configuration: types, autocomplete, input mode, password toggles
grep -rnE '<(input|Input|TextField)[^>]*name="(email|phone|tel|url|password|zip|postal|cc|card)[a-zA-Z]*"' --include='*.tsx' . | grep -v node_modules | grep -vE 'type=' | head
grep -rnE '<(input|Input|TextField)' --include='*.tsx' . | grep -v node_modules | grep -cE 'autoComplete=|autocomplete='; grep -rnE '<(input|Input|TextField)' --include='*.tsx' . | grep -v node_modules | wc -l
grep -rnE 'inputMode=' --include='*.tsx' . | grep -v node_modules | wc -l; grep -rnE 'type="password"' --include='*.tsx' . | grep -v node_modules | wc -l; grep -rnE 'showPassword|togglePassword|EyeIcon' --include='*.tsx' . | grep -v node_modules | wc -l

# 3. Labels, required markers, hints
grep -rnE '<(input|Input|TextField)[^>]*placeholder=' --include='*.tsx' . | grep -v node_modules | grep -vE 'aria-label|<label|label=' | head
grep -rnE 'htmlFor=|<label' --include='*.tsx' . | grep -v node_modules | wc -l; grep -rnE 'required|aria-required' --include='*.tsx' . | grep -v node_modules | wc -l

# 4. Validation timing, messages, and rules
grep -rnE 'mode:\s*["'"'"'](onBlur|onChange|onSubmit|onTouched|all)|reValidateMode' --include='*.tsx' --include='*.ts' . | grep -v node_modules | head
grep -rnoE '(message|error):\s*["'"'"'][^"'"'"']{3,60}' --include='*.ts' --include='*.tsx' . | grep -v node_modules | grep -iE 'invalid|required|wrong' | sort | uniq -c | sort -rn | head -10
grep -rnE 'regex\(|\.regex\(|new RegExp\(|pattern=' --include='*.ts' --include='*.tsx' . | grep -v node_modules | grep -iE 'name|email|phone|address|zip' | head
grep -rnE 'z\.object\(' --include='*.ts' . | grep -v node_modules | grep -iE 'form|schema' | wc -l

# 5. Submission feedback, input preservation, mobile
grep -rnE 'isSubmitting|isPending|disabled=\{' --include='*.tsx' . | grep -v node_modules | grep -iE 'submit|button' | wc -l; grep -rnE 'reset\(\)' --include='*.tsx' . | grep -v node_modules | grep -iE 'catch|error' | head
grep -rnE 'text-(xs|sm)' --include='*.tsx' . | grep -v node_modules | grep -E '<(input|Input)' | wc -l
# (fill every form on a phone emulator with autofill and a typo; tab through on desktop; run a screen reader on one form; keep screenshots)

Methodology: Inventory the forms and fill each one as a user would: with autofill on desktop, with a thumb on a phone, with a typo, with a valid but unusual value (an accented name, an international phone, a plus-addressed email), and with a failed submit. Record every point where the browser could not help, the keyboard was wrong, the page zoomed, the error was unclear, the input was lost, or the button could be pressed twice. Read the schemas for the rules and compare client with server. Run a screen reader on one representative form for announcements and focus. Rank by the form's importance (signup and checkout first) and the share of users the friction affects.

Input Configuration

  • Every field with the right type, autocomplete token, and input mode; password fields with a visibility toggle and the rules shown before typing; limits exposed with counts where they exist; textareas that grow

Labels & Hints

  • Visible labels associated with inputs, placeholders used only as examples, required fields marked consistently, format hints for dates, phones, codes, and anything with a convention

Validation & Messages

  • Validation on blur with revalidation on change once a field has erred, server rules mirrored on the client, messages beside the field that name the rule and the fix, errors cleared when corrected, the first error focused on submit, one error at a time per field, and rules tested against valid unusual values

Submission & Preservation

  • Pending state and double-submit protection on the button, input preserved on any failure, a clear success confirmation with the next step, and server errors mapped to fields where they belong

Mobile & Accessibility

  • Fields at the size that prevents zoom, the keyboard matched to the field, the active field and the submit button visible above the keyboard, next-field flow working, errors announced, required state exposed

Evidence rules: Confirmed requires the walkthrough: the keyboard shown on the phone screenshot, the zoom on focus, the error message as rendered, the cleared field after a failed submit, the duplicate submission, the rejected valid value, or the screen reader's silence on an error. A gap from the attributes alone is Likely until filled in. Forms that pass are reported as such with the fills recorded. Defer to the product's own form components where they supply the behaviour, and say where forms bypass them.

Output Format

Start with a 3–5 line executive summary: forms audited, the most important form's friction points, validation timing and message quality, mobile state, and the first fix.

Form table:

Form Fields Types and autocomplete Labels and hints Validation timing Message quality Rules (strict or loose) Input preserved Pending and double-submit Success feedback Mobile keyboard and zoom Announced Status

Findings: each with form, field, the walkthrough evidence, severity (Critical for input lost on failure, double submits, valid values rejected on signup or checkout; High for placeholder-only labels, submit-only validation, unhelpful messages, zooming inputs; Medium for missing autocomplete and hints, missing success feedback; Low for polish), and fix. Positive findings. Omit any section with nothing to report.

Want this applied to a live stack?

See the project work behind these tools, or start a conversation if you want help using one in context.

View the prompt source as JSON