Forms — the most common UI, and the easiest to get wrong
Nearly every product has forms — signup, checkout, settings — and nearly every product gets some part of them wrong: unclear labels, validation that interrupts before a user finishes typing, error messages that don't say what to actually do. Small, specific rules fix most of it.
Intermediate
3 min read
Labels: always visible, never only a placeholder
A placeholder (text inside an empty input, like a hint) disappears the moment
a user starts typing — if it was the only label, the user now has to
remember what field they're filling in, or scroll back up to check. A real,
persistent label should sit above or beside the input, visible the entire
time, with the placeholder (if used at all) reserved for a genuine example of
expected input format, not the field's identity.
❌ [ Enter your email... ] <- placeholder as the ONLY label
✅ Email
[ you@example.com ] <- persistent label, placeholder as an example
Validation timing: don't interrupt someone still typing
Showing "invalid email" the instant a user types their first character is a
genuinely common, actively frustrating mistake — the field isn't finished yet,
of course it doesn't match. Validating on blur (when the user leaves the
field) or on submit for the first check, then switching to live validation
after an error has already been shown (so a fix is confirmed the moment it's
actually correct), respects that a user is mid-task rather than treating every
keystroke as a final answer.
Error messages: specific and actionable, never just "invalid"
"Invalid input" tells a user something is wrong but nothing about what to
actually change — genuinely useless as guidance. A good error message states
exactly what's wrong and, where possible, exactly how to fix it:
❌ "Invalid input"
❌ "Error"
✅ "Password must be at least 8 characters"
✅ "This email is already registered — try logging in instead"
Only ask for what you actually need, right now
Every additional field is a real cost — more time, more chances for a user to
hesitate or abandon the form entirely. A field that isn't strictly necessary
for the immediate task (a phone number collected "just in case," a full
address collected before a user has even added anything to a cart) should be
deferred to when it's actually needed, or removed from the form entirely if
it's not.
Grouping related fields visually
The spacing lesson's grouping principle applies directly to forms: fields that
belong together (first name and last name; city, state, and zip) should sit
closer together than fields from a different logical group, using the
whitespace itself to communicate the form's actual structure before a user
reads a single label.
Button labels should say what happens, not just "Submit"
A button labeled "Submit" tells a user nothing about the actual consequence of
clicking it. A button labeled with the specific action — "Create account,"
"Save changes," "Place order" — sets an accurate expectation, and (this
domain's affordances lesson ahead covers this further) confirms itself with a
matching result, like a toast that says "Changes saved" after a "Save changes"
button is clicked.