The best forms follow a short set of rules. Use one column with the label above each field. Pick the input type that fires the right mobile keyboard. Validate on blur, then re-check on submit with a summary. Write errors that say what to do. Wire the form for a screen reader. And never lose typed data after a failed submit. Those are the form design best practices worth memorizing.
Most guides stop at the surface craft. But a form is where design meets validation, state, and accessibility in code. This is how to design any single form well. App forms, checkout, and lead capture are separate jobs, linked at the end.
1. Put the label above the field, never inside it
Put the label directly above the input. It stays visible while someone types. It survives narrow mobile widths without truncating. And it keeps the whole form in one clean reading column.
A placeholder is not a label. Placeholder text disappears the second someone starts typing. Its low contrast gray also reads as a field that is already filled, so people skip it.
Use a placeholder only for a format hint, like a date pattern. Even then, a hint line below the field is safer, because it stays put.
2. Mark the minority: required vs optional
Mark whichever set is smaller. If most fields are required, mark the few optional ones. If most are optional, mark the required ones instead.
An asterisk on every single field marks nothing. A signal on everything is a signal on nothing.
Prefer the plain word optional over a lone asterisk. Picture a signup form with eight required fields and one optional phone number. Label just that one: Phone (optional). Now the exception is obvious at a glance.
3. One column, grouped so related fields sit together
A single column beats a multi column layout. Two columns make the eye zigzag, and people miss fields on the right. One column reads straight down.
The one exception is genuinely paired data. City and postal code can share a row. So can a card expiry and its security code. They belong together and read as one unit.
Group related fields under small headings. A long form then reads as a few short sections: Your details, Shipping, Payment. Order the fields the way a person actually thinks about the task.
4. Match the input type to the mobile keyboard
Every guide says use the right input type. Few say what that buys you. On mobile, it changes the keyboard under the field.
type=email brings up a keyboard with the @ and .com keys ready, and it turns on the browser native email format check for free. type=tel brings up the phone dial pad, but it does no format validation on its own, because phone numbers vary too much across countries to check.
inputmode tunes the on screen keyboard without changing validation. inputmode=numeric gives a digits only pad for a verification code. inputmode=decimal adds the decimal point for a price.
Then there is the most skipped attribute of all: autocomplete. The right token lets the browser fill the field from saved data. autocomplete=email, autocomplete=tel, autocomplete=cc-number, autocomplete=one-time-code. That last one can pull a texted code straight from the keyboard suggestion bar.
Here is the mapping worth keeping close.
| Field | Input attribute | autocomplete token | Mobile keyboard result | |---|---|---|---| | Email | type=email | email | Keyboard with @ and .com keys | | Phone | type=tel | tel | Numeric phone dial pad | | Numeric code | inputmode=numeric | one-time-code | Digits only number pad | | Street address | type=text | street-address | Standard text keyboard | | Postal code | type=text | postal-code | Standard alphanumeric keyboard | | Credit card number | inputmode=numeric | cc-number | Digits only number pad |
5. Validation timing is an engineering decision, not a style choice
This is the section every ranking guide skips. Validation is not a visual style. It is a timing decision you make in code, and the timing changes everything.
Validate on change, and you fight the user. Someone typing an email address sees "Invalid email" flash before they reach the @. That is hostile.
Validate on blur, and feedback arrives at the right moment: when the person finishes a field and moves on. Better, but not enough alone. A field they skipped entirely never blurred, so it never got checked.
Validate on submit only, and a single bad field sends them scrolling back through the whole form to find it.
The answer lives almost nowhere on the head term. Combine them. Validate each field on blur. Re-check the whole form on submit. Show a short summary of what failed, and move focus to the first bad field. I call it blur plus submit. It is the pattern I reach for on every build.
| Approach | What it does | The problem | When to use | |---|---|---|---| | on change | Checks after every keystroke | Flags a half typed email as wrong | Rarely, only for strength meters | | on blur | Checks when a field loses focus | Misses a field skipped entirely | The default for most fields | | on submit | Checks everything at the end | Sends people hunting for the one bad field | Never on its own | | on blur plus on submit | Blur feedback, full re-check at submit | None worth avoiding | The recommendation |
6. Write error messages that say what to do, not just what is wrong
An error should name the fix, not just the fault. "Invalid date" tells someone nothing. "Enter a date in the future" tells them exactly what to change.
Put the message right next to the field. A summary at the top is useful too, but the fix belongs where the eye already is.
Be specific about the rule that broke. "Password too short" is vague. "Use at least 8 characters" is actionable. Same for allowed characters, or an email already taken.
Never blame the person. Describe the requirement instead. The form asked for something specific, so say what that something is.
7. Preserve everything on a failed submit
When a submit fails, the user should never re-type a thing. Keep every value. Text, yes, but also the selects, the radios, and the checkboxes they already set.
A form that clears itself on error is a form people abandon. They typed all that once. They will not do it twice.
This bites hardest at the register, so a checkout form has its own field rules, covered separately.
Know the client side versus server side reality. In the browser, the values are already there, so a failed check keeps them by default. A server round trip is different. If the request goes to the server and comes back with an error, your code has to repopulate every field from the submitted data. A naive server render resets the form to blank. That is the bug that quietly kills completion.
8. Make the form usable with a screen reader
This is the rule no head term winner covers, and it is the clearest sign a form was built, not just drawn. A form can look perfect and be unusable for someone who cannot see it.
Four attributes do most of the work. Set aria-invalid=true on a field that failed, so a screen reader announces it as an error. Point aria-describedby at the id of the error text, so the message reads out together with the label. Wrap errors that appear after load in an aria-live=polite region, so they announce without a page reload. And on a failed submit, move keyboard focus to the first invalid field.
One rule underpins all of it. Every input needs a real label, associated in code through a matching for and id pair or a wrapping label element. Visual proximity is not enough. A screen reader reads the association, not the position on screen.
Test it the honest way. Turn on VoiceOver on a Mac or NVDA on Windows, then tab through your form with the screen off. If you cannot tell which field failed and why, neither can your user.
9. Name the action on the submit button
The button should name the outcome. Create account. Place order. Send message. "Submit" tells the person nothing about what happens next.
Keep one primary action. If a secondary action exists, like Save draft, make it visibly quieter so the main path stays obvious.
Do not disable the button until the form is perfect. A dead button with no reason confuses people. Keep it live and validate on click instead.
Show a loading state the moment it is clicked. That confirms the tap and blocks a double submit.
10. Single page or multi step: decide by length and context
Short form? One page. Do not split three fields across three steps and add clicks for no reason.
Multi step earns its place for a long or naturally grouped flow: an application, an onboarding sequence, a booking. Break it where the task breaks, not at a random point.
When you do split it, show a progress indicator so people know how far they have to go. Make back navigation safe, so a wrong turn costs nothing.
Rule 7 still holds across steps. Moving forward, moving back, or timing out must never wipe what someone already entered.
Forms in a product are a different problem
Everything above is how to design one standalone form well. Two contexts change the rules enough to treat separately.
The first is forms inside an app someone uses every day. Those are long, repeated, and filled by trained users, so they follow a different playbook.
The second is a lead capture form has a different job, where the goal is a conversion, not a complete record. The tradeoffs shift toward the first field and the reason to start.
The build side is where a form actually wins
Layout is table stakes. Labels above fields, one column, a clear button: any competent designer gets there. The forms that actually win are wired well underneath.
The rules that matter most are the ones most guides skip. Validation timing done as blur plus submit. A screen reader wired with aria-invalid and aria-describedby. Input types mapped to the right mobile keyboard. And a form that never loses a keystroke on a failed submit.
That is the line between a form that looks done and a form that is done. It is design and engineering meeting in the same file.
If you want a form designed and shipped that clears every rule here, that is the work I do.