Pavle
Design Engineering

Form Design Best Practices: 10 Rules for Forms People Finish

Pavle Lucic
Pavle LucicJuly 23, 2026 · 10 min read
Key takeaways
  • Put the label above the field and never use the placeholder as a label. Placeholder text vanishes the moment someone types, taking the field's name with it.

  • Mark the minority. If most fields are required, mark the optional ones instead. An asterisk on every field is a signal on nothing.

  • Validation timing is an engineering decision. Validate a field on blur, re-check on submit with a summary, and move focus to the first error. On blur alone can still lose the user on submit.

  • Match the input type to the keyboard. type=email and type=tel plus inputmode and the right autocomplete token drive the mobile keyboard and browser autofill that most guides mention only in passing.

  • A screen reader needs aria-invalid, aria-describedby tying the error to the field, and focus moved to the first error on a failed submit. Without that wiring the form is unusable for anyone not looking at the screen.

On this page

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.

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.

Tip

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.

Frequently asked questions

Should form labels go above or beside the field?

Above the field. A label above the input stays visible while typing, works on narrow mobile screens without truncating, and keeps a single reading column. Labels beside the field force awkward wrapping on small screens and break the top to bottom scan.

When should you validate a form, on blur or on submit?

Combine both. Validate a field on blur so the user gets feedback as they finish each field, then re-check everything on submit and show a summary. Validating on every keystroke is hostile, and validating only on submit sends people hunting back through the form for the one bad field.

Should you mark required or optional fields?

Mark whichever set is smaller. If most fields are required, mark only the optional ones with the word optional. If most are optional, mark the required ones. Putting an asterisk on every field marks nothing, because a signal on everything is a signal on nothing.

How do you make a form accessible to screen readers?

Tie the error to the field in code. Set aria-invalid on the field, point aria-describedby at the error text so a screen reader reads it with the label, announce errors that appear after load through an aria-live region, and move focus to the first invalid field on a failed submit.

What input type should you use for phone numbers and email on mobile?

Use type=email for email and type=tel for phone numbers, which switch a mobile device to the matching keyboard. Add inputmode=numeric for numeric codes and the correct autocomplete token, such as email or tel, so the browser can offer autofill.