Skip to content
Web engineering6 min read

Forms: the highest-stakes, least-designed part of most products

A form is where a visitor becomes a customer, and it is routinely the least considered surface in a product. The failures are consistent and cheap to fix: validation that fires while typing, errors that say what is wrong but not what to do, and a submission failure that discards everything the person entered.

Part ofWeb & Portal Development

Every other page on a site can be imperfect and still do its job. A form that loses someone's input, or rejects it without explaining why, converts intent into abandonment. The engineering is not difficult — it is just rarely given the attention the stakes justify.

Ask for less

Before any implementation question, there is a content one: is every field necessary? Each additional field costs completion rate and creates a retention obligation under data-protection law.

  • Delete any field nobody uses. Audit against what is actually read, not what someone once requested.
  • Do not ask for what you can derive — country from a dialling code, city from a postcode lookup.
  • Split genuinely long processes into steps with visible progress, rather than one intimidating page.
  • Mark optional fields rather than required ones when most are required; mark required ones when most are optional. Whichever is rarer.

Validation timing decides whether it feels hostile

Validating on every keystroke means telling someone their email is invalid while they are still typing the second character. It is the most common form annoyance and the easiest to fix.

EventValidate?Why
On keypress, field never validNoPunishes typing in progress
On blur, after first interactionYesThey have finished; now feedback is useful
On keypress, field already invalidYesClear the error as soon as it is resolved
On submitAlwaysFinal gate; move focus to the first error

The rule in one line: be slow to complain and quick to forgive. Wait until they leave a field before flagging it, then remove the flag the instant it becomes valid.

Error messages that can be acted on

An error message has one job: tell the person what to do next. Most tell them only that something is wrong, which they already knew from the red border.

UnhelpfulActionable
Invalid inputEnter a date as DD/MM/YYYY, for example 14/03/2026
This field is requiredWe need an email address to send your confirmation
Password does not meet requirementsAdd one number — everything else looks fine
Invalid phone numberInclude the area code, without spaces
Something went wrongWe could not reach the payment provider. Your details are saved — try again in a moment

Markup that works with assistive technology

Accessible form markup is a small, fixed set of associations. Getting them right takes no longer than getting them wrong.

tsx
// label→input association by id, error tied via aria-describedby,
// invalid state exposed, and autocomplete so password managers and
// browser autofill both work.
<label htmlFor="email">Email address</label>
<input
  id="email"
  name="email"
  type="email"
  autoComplete="email"
  inputMode="email"
  required
  aria-invalid={error ? true : undefined}
  aria-describedby={[hint && "email-hint", error && "email-error"]
    .filter(Boolean)
    .join(" ") || undefined}
/>
{hint ? <p id="email-hint">We only use this to reply.</p> : null}
{error ? <p id="email-error" role="alert">{error}</p> : null}
  • Every input has a real <label> with a matching htmlFor — placeholder text is not a label and vanishes on typing
  • autocomplete tokens let browsers and password managers fill correctly; omitting them is a real usability cost
  • inputMode gives mobile users the right keyboard — numeric for codes, email for addresses
  • Group related inputs in a <fieldset> with a <legend>, especially radio sets
  • On submit failure, move focus to the first invalid field so keyboard and screen-reader users are taken to it

Spam control without punishing humans

CAPTCHA is an accessibility problem, a conversion cost and increasingly ineffective against automated solvers. For most forms, cheaper measures work better.

  1. Honeypot field — hidden from sighted users and from assistive technology, so any value means automation. Respond as though submission succeeded rather than revealing the check.
  2. Timing check — reject submissions that arrive faster than a person could plausibly type. Stamp the render time client-side, verify server-side.
  3. Rate limiting — per IP and per identifier, which also protects against enumeration.
  4. Server-side validation of everything — the only control that matters, since client validation is a convenience a bot ignores entirely.

Reach for a challenge only when those four have measurably failed, and prefer a modern invisible challenge over an image puzzle when you do.

The four states every form needs

Most forms are built for the happy path and acquire the other states as bug fixes. Designing all four up front is what makes a form feel solid.

StateRequirement
IdleClear labels, visible required markers, sensible defaults
SubmittingButton disabled and labelled ("Sending…"), so double-submission is impossible
ErrorValues preserved, errors attached to fields, focus moved, an actionable message
SuccessUnambiguous confirmation announced to assistive technology, and what happens next

The test worth running before launch

  1. Complete it using only the keyboard, and confirm focus lands on the first error when submission fails.
  2. Submit it with every field empty, and read each message as a stranger would.
  3. Submit it with valid data while the backend is unreachable, and confirm nothing entered is lost.
  4. Fill it with a password manager and browser autofill, and confirm the right values land in the right fields.
  5. Complete it on a phone, one-handed, and check the keyboard type on each field.

Questions

When should form validation run?

On blur after the field has been interacted with, on keypress only once a field is already invalid so the error clears immediately, and always on submit. Validating every keystroke from the first character tells people their input is wrong while they are still typing it, which is the single most common form annoyance.

Do I need a CAPTCHA?

Usually not. A hidden honeypot field, a timing check, per-IP rate limiting and thorough server-side validation stop most automated submissions at no cost to real users. CAPTCHA adds an accessibility barrier and a conversion cost, and automated solvers have substantially reduced its effectiveness — treat it as an escalation, not a default.

Is placeholder text an acceptable substitute for a label?

No. Placeholders disappear as soon as someone types, so the field loses its description exactly when it is being filled, and support for them in assistive technology is inconsistent. Use a visible label associated by id; a placeholder is for an example value, not for the field's name.

What is the most damaging form bug?

Discarding entered data when submission fails. Everything else is an irritation; this destroys work someone already did and reliably ends the session. Preserve all values, re-render with errors attached, and treat the submitted payload as something you are responsible for not losing.

Want this applied to your systems?

Most of what is described here begins as an assessment: a fixed-scope review producing a prioritised written report you can act on with any supplier.

Prefer email? hello@kornspire.com