ContentsAct II · MakeDesign it yourself
Move 24
Blur, don't punish
The form turns a field red while the user is still typing their own name. The browser has known how to avoid this since 2023.
A participant in a usability study, describing a registration form:
“When I clicked in the First Name field, it immediately came up saying that my first name is too short.”
And another, on the same class of failure:
“It’s frustrating that you don’t get the chance to put anything in the field before it’s flashing red at you.”
Both of those are your form, if you validate on keystroke. The user has done nothing wrong. They have started, and your interface has responded by telling them they are already failing.
What is genuinely contested, and what is not
I want to separate two questions that usually get argued as one, because the fact bank flags this move’s evidence as disputed and it deserves resolving properly.
Contested: inline validation versus validating on submit. The widely cited case for inline comes from Luke Wroblewski’s work with Etre, testing “22 average users on six variations of a typical web registration form.” Against it sits Bargas-Avila and colleagues, peer reviewed, at n=77 and n=90, who reached the opposite conclusion and published the recommendation “Always show error messages after the form has been filled and sent.”
Twenty-two participants against a hundred and sixty-seven, with the larger studies peer reviewed. So if somebody tells you inline validation is proven, they are quoting the smaller number. I am not going to settle that question here and neither should you.
Not contested: when to show it, if you are showing it inline. On this, both camps and the platform agree, and even Wroblewski’s own data does. Within his study, showing the message after the user left the field beat showing it while they typed: participants completed the form “seven to ten seconds faster” with the after method.
That is this chapter’s question, and it has an answer nobody disputes.
The move
Show the error when they leave a field they actually edited, never while they type, never on an empty required field before submit, and clear it the moment they start fixing it.
The browser already does exactly this
Here is the part that makes this mechanical rather than a matter of taste.
The HTML Standard defines a control’s user validity flag, and sets it in exactly three
places: when a change is committed, when the user unfocuses a field they actually edited, and
on submit, for every field in the form. The CSS pseudo-class :user-invalid matches only when
that flag is true and the constraints are unsatisfied.
Read those three trigger points against the three rules above. They are the same three rules. Not while typing, because the flag is not set. Not on an empty field the user never touched, because they did not edit it. On submit, everything, because submit sets it for the whole form.
This has been Baseline widely available since November 2023. The behaviour you are writing hundreds of lines of state management to approximate is a pseudo-class.
/* BEFORE: fires on every keystroke, including the first */
.field.invalid { border-color: red; }
/* plus onChange handlers, touched/dirty flags, a validation
library, and a bug where the error persists after the fix */
/* AFTER */
input:user-invalid {
border-color: var(--danger);
}
input:user-invalid + .error-message {
display: block;
}
/* nothing fires while they type.
nothing fires on a field they never touched.
everything fires on submit.
it clears itself when the value becomes valid. */
The one documented exception
Wroblewski found a real case for validating during typing, and it is narrow: fields with strict boundaries the user cannot see. He used the while method with a short delay for username and password “for questions with strict boundaries, such as the” availability of a username.
That makes sense. Waiting until blur to discover that a username is taken, or that a password fails a rule you never displayed, wastes a round trip through the user’s attention. Everywhere else, blur.
What it costs
Success ticks are mostly noise, and there is data on it. In Wroblewski’s study, only 30 to 50% of participants even noticed validation messages in the first half of the forms, against 80 to 100% in the second half. Participants reacted to green ticks on trivial fields with variations of are you telling me I entered a valid name? Confirm the things that are genuinely uncertain, not the things nobody could get wrong.
And :user-invalid only knows what the browser knows. It covers required, type,
pattern, min and max. Anything server-side, a username already taken, a code that has
expired, still needs your own state. The win is that the platform handles the common cases and
the timing, so your code only handles the genuinely custom ones.
Try this week
Open your longest form, click into the first field, and type one character of something valid. Then delete it.
If anything turned red at any point in that sequence, you are validating on keystroke.
Then replace one field’s validation with :user-invalid and delete the state that was
tracking whether it had been touched. Most of the time that is a net deletion of code, and the
behaviour gets better rather than worse, which is not a trade you are offered often.