How to Prototype a Form with Real Validation States
Form prototypes fail in a specific, predictable way. Someone builds a beautiful signup screen in Figma, wires it to a clickable flow, records a Loom, and the whole thing looks convincing until a reviewer types three letters into the email field and nothing happens. No red text. No green check. The prototype is a picture of a form. It cannot tell anyone whether the form actually works.
The fix is not more design polish. It is putting real validation states into the prototype early enough that the states themselves become design material. Error messages, disabled buttons, partial success, the awkward middle where the user has typed something wrong and the interface has to say so without insulting them. Those are the parts of a form that decide whether it gets finished.
What counts as a real validation state
A validation state is any visual or behavioral change that fires in response to what a user has entered. The obvious ones are the error and the success check. The ones that matter more and get skipped more often are the in-between states: field touched but empty, value present but malformed, value valid but the server has not confirmed it, value valid and the server rejected it anyway because the email already exists.
Most prototypes collapse all of those into one red outline. That is why reviewers approve them and engineers rebuild them. A prototype that shows only the happy path and a single error look has tested nothing about the hardest part of the job.
The working definition worth carrying into a build: a prototype has real validation states when a person can trigger every state the production form will show, using the same inputs that will trigger them later. If the trigger is fake, the state is fake.
Map the states before building any of them
Before opening a prototyping tool, list every field and every state each field can enter. A four-field signup form with three states per field is twelve cells. Most of them are boring. Two or three are hard, and those are the ones that will eat a week of engineering time if nobody designed them.
The listing takes an hour and saves the argument later. It also exposes fields that were never specified. A password field with a strength meter has at least four states: empty, weak, acceptable, strong. Nobody designed the acceptable one. The acceptable state is where users get stuck, because the meter says nothing is wrong but the submit button stays gray and the interface never explains why.
Write the list as a table with columns for trigger, message text, field styling, and what the submit button does. The message text column is the one people skip and the one reviewers judge hardest. "Invalid input" is a state that exists in the prototype and fails in production.
Build the error message as a component, not as text
Error messages get treated as copy that lives inside the field component. That works until the same message needs to appear above the field on mobile and below it on desktop, or until it needs an icon, or until the layout shifts when it appears and the submit button jumps under the user's thumb mid-tap.
A message component with slots for text, icon, and severity level keeps the prototype consistent and makes the layout shift visible during testing. Layout shift is a validation bug, not a styling detail. If the error pushes the button down by 24 pixels and the user was already reaching for it, the form just punished them for typing.
Reserve the space. The prototype should show the empty reserved area in the default state so anyone reviewing it sees the cost up front. Forms that reserve error space feel calmer because nothing moves. Forms that do not reserve it feel twitchy, and the twitch is the first thing users notice and the last thing they can name.
Timing: when validation fires is a design decision
Validating on every keystroke means the email field turns red after the first character. Validating on blur means the user can tab past a broken field and never see the error until they try to submit. Both are wrong, and the right answer is more specific than either.
The pattern that survives contact with real users: do not validate a field until it has been touched and left, then revalidate as the user corrects it. The first error appears on blur. Once the field is in an error state, it updates on every keystroke so the red clears the moment the input becomes valid. That gives a person immediate feedback while they fix the problem and silence while they are still typing the value for the first time.
A prototype has to model this timing or it lies. A static red state in Figma proves nothing about whether the error appears at the wrong moment. Wiring the blur event in a tool like Framer or a small React sandbox is the difference between reviewing a picture and reviewing behavior.
Let the submit button carry state instead of hiding it
Disabled submit buttons are a common default and a quiet trap. A grayed-out button communicates that something is wrong without saying what. The user scans the form, finds no red text because nothing has been touched yet, and concludes the form is broken.
The alternative worth prototyping: the button stays enabled, and pressing it surfaces the first error and scrolls to it. The button also gets its own loading state for the moment between press and server response, because that gap is where double submissions happen. A prototype that shows the loading state and the disabled-during-request state will surface the question of what happens if the request fails, which is a state almost every prototype omits and almost every production form needs.
If the button must be disabled, the prototype should at least show why. A short line above the button that names the missing requirement beats a gray rectangle with no explanation.
Server-side states need a stub, not a mockup
Some validation cannot happen in the browser. Whether an email is already registered, whether a username is taken, whether a promo code is live. These are the states most likely to be designed wrong because they require a round trip and most prototypes do not make one.
A stub is enough. A tiny endpoint that returns a fixed set of responses based on the input, so typing a specific address returns "already registered" and anything else returns success. The stub does not need a database. It needs to be slow enough to show the pending state, which means an artificial delay of a few hundred milliseconds, because the pending state is exactly what the designer needs to see.
The pending state for an async check has its own design problems. The field shows a spinner, the user keeps typing, the spinner resolves for the old value and paints the field green while the current value is different. That race condition is invisible in a static mockup and obvious in a stub. Finding it in a prototype costs an afternoon. Finding it after launch costs a support ticket and a hotfix.
Test the prototype with the inputs that break it
A prototype with real validation states is only useful if someone tries to break it. The review session needs a script of hostile inputs: a name with an apostrophe, an email with a plus sign, a phone number in international format, a password pasted from a manager, a field left empty and blurred, a value that is valid but already taken.
Each of those inputs should produce a designed response. If the prototype crashes, freezes, or shows a raw browser tooltip, that is a finding. The raw browser tooltip is worth calling out specifically, because it is the default behavior of the required attribute and it looks different in every browser, which means the design was never actually in control of the error state.
Handoff: ship the states, not the screens
The prototype's real output is not a set of screens. It is a state table with every cell filled and a working reference implementation that engineers can read. When the handoff includes the trigger logic, the message copy, the timing rule, and the async stub, the engineering conversation shifts from "what should this do" to "how do we match this." That shift is worth more than any amount of visual polish.
The prototype that shows a green check and a single red outline will get approved by people who never typed into it. The prototype that shows the field mid-typing, the spinner racing the cursor, and the error that clears itself the moment the input becomes valid will get questioned, and the questions are the point. A form is a conversation with rules, and the rules are only visible when someone tries to break them.

