Skip to content

Interface

Forms that do not lose work, and errors people can act on

The worst thing a form can do is not rejecting bad input. It is accepting twenty minutes of careful work, failing somewhere invisible, and leaving somebody with an empty screen and no idea what to retype.

The short answer

Never discard input on failure. Surface an error in three places at once, at the field, in a summary beside the submit, and as a transient message, because each is read in a different situation. Validate on leaving a field rather than on every keystroke, and disable a submit only while a request is genuinely in flight.

The failure that actually matters

Every form has two failure modes and only one of them gets designed for.

The one that gets attention is bad input: a missing field, a malformed number. That is easy, and every library on earth handles it.

The one that ruins somebody’s afternoon is the request that fails after they submitted twenty minutes of careful work. The network dropped, the session expired, the server had a moment. If the response to that is a cleared form, you have not displayed an error, you have destroyed work.

Rule one: input is sacred. Never clear a form on failure. Never navigate away from unsaved input without asking. If the submit fails, everything they typed is still there and the error explains what to do next.

Three surfaces, because there are three situations

An error needs to appear in three places at once. This looks redundant until you think about where the person is actually looking.

  • At the field. For somebody whose eyes are on that field, correcting it.
  • In a summary beside the submit. For somebody who just pressed the button and is wondering why nothing happened. On a long form the failing field can be entirely off screen, so this summary must link to it.
  • As a transient message. For somebody whose attention had left the page. This one also carries the failures that belong to no field at all: the network, the session, the server.

Drop any one of the three and there is a real situation in which somebody is staring at a screen that appears to have silently ignored them.

Validate when it helps

On blur, and again on submit. That is the whole rule.

Validating on every keystroke means telling somebody their email address is invalid while they are typing the first letter of it. It is correct and useless, and it trains people to ignore your error styling, which then fails to work on the occasion that matters.

The exception is a field with a live constraint the person is working against, such as a character count or a strength meter. There the running feedback is the entire point.

Disabled buttons are usually a bug

A submit disabled until the form is valid seems helpful. In practice somebody fills in a long form, finds nothing is pressable, and cannot work out which field is at fault. The disabled state hides exactly the information they need.

Let them submit. Then tell them precisely what is wrong, in the three places above. The only legitimate reason to disable a submit is that a request is already in flight, and in that case the button should say so rather than merely turning grey.

Never punish a slow network

Somebody on a slow connection did not choose it, and operational software is very often used in exactly those conditions.

Give the button an in flight state so nobody presses it twice. Make the submit idempotent on the server so that it does not matter when they do. Time out generously, because an aggressive timeout on a slow connection converts a working submission into a lost one. And when it does fail, say clearly whether anything was saved, so the person knows whether retrying will create a duplicate.

That last sentence is the difference between an error message and an actual answer.

Questions people actually ask

Why surface the same error three times?
Because the three are read in different situations. The field error is for somebody looking at that field. The summary is for somebody who pressed submit and is looking elsewhere on the form. The transient message is for somebody whose attention had left the page entirely. Any one alone misses a real case.
When should validation fire?
On leaving a field, and again on submit. Validating on every keystroke tells somebody their email address is invalid while they are still typing the first letter of it, which is true and completely useless.
What about very long forms?
Save progress locally as they go, and tell them you are doing it. An apology after losing an hour of somebody's work is never worth as much as not losing it.

Published June 2026, updated July 2026.

Hiring someone to own work like this?

I am open to senior backend and full stack roles, remote and permanent.

Get in touch / Read the CV