Validate the same rules on both the client and the server — the client validation is UX, the server validation is the actual security boundary.
Client-side validation is a courtesy, not a boundary
- Never trust client-side validation as the source of truth — it exists purely to give the user fast feedback. Every rule enforced client-side must be re-enforced server-side, because the client can always be bypassed (disabled JS, direct API calls, a modified request).
- Validate on submit at minimum; validate on blur for immediate per-field feedback once the user has interacted with a field — but never flag a field as invalid while the user is still mid-typing on their first pass through it (e.g. don't mark an empty required field red before they've touched it).
Error messages
- Error messages must say what's wrong AND how to fix it: "Password must be at least 12 characters" beats "Invalid password." Never show a raw backend error string or a stack trace to the user.
- Show errors next to the field they belong to, not only in a summary banner at the top — a banner alone forces the user to hunt for which field is broken, especially on long forms.
- Preserve the user's input on validation failure. Never clear a form (or a single field) because one other field failed validation — that's one of the most reliably infuriating UX mistakes in form design.
Required vs optional
- Mark required fields clearly and consistently (a single method — asterisk, "required" label — used the same way everywhere in the app). If most fields are required, consider marking the few optional ones instead, which reduces visual noise.
- Never silently strip or ignore invalid input server-side; always reject with a clear error, since silently coercing input can hide bugs and exposes internal validation logic to attackers probing for it.
Submission behavior
- Disable the submit button (or show a loading state) immediately on submit to prevent duplicate submissions from a double-click or slow network — but always pair this with server-side idempotency, since disabling a button is a UX nicety, not a guarantee.
- Never lose unsaved form data on a transient network failure — surface a retry option and keep the user's input intact rather than resetting the form.
Accessibility of validation
- Associate every error message with its field via
aria-describedby, and set aria-invalid="true" on the invalid field — a red border alone communicates nothing to assistive tech; validation errors must be programmatically discoverable, not just visual.
Edge cases to always handle
- Whitespace-only input in a "required" field should be rejected, not accepted as valid content.
- Copy-pasted input often carries invisible characters or unexpected whitespace — trim before validating, but store what the user actually intended.
- Autofill can populate fields in ways that skip your normal
onChange handlers in some frameworks — verify validation still triggers correctly with browser autofill, not just manual typing.
Comments (0)
Sign in to comment. Sign in
No comments yet. Be the first to add one.