Form Best Practices & UX
Getting a form to work is one thing; getting it to feel effortless is another. Most of the friction people feel filling out a bad form comes down to a small set of recurring mistakes — missing labels, vague error text, keyboard traps, and mobile keyboards that don't match the data being entered. None of these require a framework to fix.
1. Label Every Input, Always
Every form control needs a real <label>, connected with for/id (or by
wrapping the input). Without one, screen reader users hear nothing
identifying the field, and sighted users lose the larger click target a
label provides.
always-label.html
<!-- Bad: no programmatic association --> <span>Email</span> <input type="email" name="email" /> <!-- Good --> <label for="email">Email</label> <input type="email" id="email" name="email" />
placeholder disappears the moment the user starts typing, has poor color contrast by default, and isn't reliably announced as the field's name by every screen reader. Never use it as a substitute for a real <label> — see below.2. The Placeholder-as-Label Anti-Pattern
It's tempting to save vertical space by dropping the visible label and just showing placeholder text inside the field. This is one of the most common — and most damaging — form UX mistakes on the web.
The hint vanishes exactly when the user needs it most: while filling in the field.
Users with memory or cognitive impairments lose the field name entirely once they start typing.
Low-contrast placeholder text (common in default browser styling) is hard to read for low-vision users.
It breaks the "fill out the form, review before submitting" workflow — reviewing a filled form shows no field names at all.
placeholder-anti-pattern.html
<!-- Anti-pattern: label text lives only in the placeholder --> <input type="text" name="full-name" placeholder="Full name" /> <!-- Better: real label, placeholder used only for a format hint --> <label for="full-name">Full name</label> <input type="text" id="full-name" name="full-name" placeholder="e.g. Jane Doe" />
3. Clear, Specific Error Messages
"Invalid input" tells the user something is wrong but not what to do about it. Good error messages name the field, explain the rule, and (when possible) show exactly what's expected.
Vague (avoid) | Specific (prefer) |
|---|---|
Invalid input | Enter a valid email address, like name@example.com |
Error in field | Password must be at least 8 characters |
Required | Phone number is required so we can confirm your order |
inline-error.html
<label for="email">Email</label> <input type="email" id="email" name="email" aria-describedby="email-error" required /> <span id="email-error" role="alert"></span>
aria-describedby to point the input at the element holding its error text, so assistive technology announces the error alongside the field — not just visually next to it.4. Logical Tab Order
Keyboard and screen reader users navigate a form by tabbing through it in document order. The visual layout must match that order — a two-column form whose markup order doesn't match its visual columns is a common source of confusing, jumpy tabbing.
Write fields in the DOM in the order a keyboard user should encounter them, not just in whatever order looks right visually with CSS.
Avoid
tabindexvalues greater than 0 — they create a second, hard-to-maintain tab order that fights with the natural one.tabindex="0"(join natural order) andtabindex="-1"(programmatic focus only) are the only values worth reaching for.Group related fields together, both visually and in the DOM, using
<fieldset>where appropriate.
5. autocomplete for Faster, Better Fills
The autocomplete attribute tells the browser (and password managers)
what kind of data a field expects, enabling accurate autofill instead of
guesses based on the field's name or label.
autocomplete.html
<label for="name">Full name</label> <input type="text" id="name" name="name" autocomplete="name" /> <label for="email">Email</label> <input type="email" id="email" name="email" autocomplete="email" /> <label for="street">Street address</label> <input type="text" id="street" name="street" autocomplete="street-address" /> <label for="new-password">New password</label> <input type="password" id="new-password" name="new-password" autocomplete="new-password" /> <label for="cc-number">Card number</label> <input type="text" id="cc-number" name="cc-number" autocomplete="cc-number" />
Value | Use for |
|---|---|
| Personal name fields |
| Email address |
| Phone number |
| Address fields |
| Login vs. sign-up password fields (different autofill behavior) |
| SMS/email OTP fields — enables automatic code fill on mobile |
| Explicitly opt a sensitive field out of autofill |
6. Mobile Keyboard Optimization
The right type and inputmode attribute switches the on-screen keyboard
to match the expected data — a numeric pad for a phone number, an @ key
front-and-center for email — saving taps and reducing input errors.
mobile-keyboards.html
<!-- Numeric pad, but keep type="text" if the value can have leading zeros --> <label for="pin">PIN</label> <input type="text" id="pin" name="pin" inputmode="numeric" pattern="[0-9]*" /> <!-- Email keyboard with @ and .com shortcuts --> <label for="email">Email</label> <input type="email" id="email" name="email" inputmode="email" /> <!-- Phone keypad --> <label for="phone">Phone</label> <input type="tel" id="phone" name="phone" inputmode="tel" />
type first (email, tel, number) — it also drives built-in validation. Add inputmode when you need a specific keyboard layout without changing the underlying value type, e.g. a numeric-only PIN that should still be treated as text (to preserve leading zeros).7. Give Feedback on Submission
Disable the submit button (or show a spinner) once clicked, to prevent duplicate submissions.
Move focus to the first invalid field, or to a success/confirmation message, after submission.
Never clear a form silently on error — the user should never have to retype everything because of one bad field.
<label>s everywhere, specific error text tied to its field, DOM order matching visual/tab order, correct autocomplete values, and mobile-friendly inputmode/type — these five habits fix the overwhelming majority of real-world form usability complaints.