HTML form validation that users don’t fight
Great validation is invisible when everything is correct and helpful when it isn’t. Modern browsers ship with powerful native checks that cover most needs: required fields, numeric/date ranges, string lengths, and patterns. Lean on these first, then layer small enhancements with the Constraint Validation API for custom messages and timing. The result is faster forms with fewer libraries and better accessibility.
Start with attributes
required
for mandatory fields; avoid overuse.min
/max
/step
for numbers, dates, and times.minlength
/maxlength
andpattern
for strings.
Feedback timing
Validate on blur or on submit. Refrain from red error states while users are still typing; it feels combative. Use :invalid
and :valid
to style states, and reportValidity()
for progressive disclosure.
Custom messages
When native messages aren’t enough, call setCustomValidity()
with a human‑readable explanation and clear it when the value becomes valid again. Keep messages short and actionable (“Enter a value from 1 to 10”).
Accessibility
- Link error text with
aria-describedby
and focus the first invalid field on submit. - Prefer inline errors near fields over banners at the top.
- Ensure a visible focus outline is preserved in error styles.
Server validation (non‑negotiable)
Client checks improve UX but can be bypassed. Re‑validate on the server, normalize and sanitize inputs, and return specific messages so users can fix issues quickly.
Practical patterns
- Form sections with logical grouping and legends for related choices.
- One error per field, placed adjacent to the control.
- Use aria‑live for dynamically updated summaries, not for every keystroke.
By combining native attributes, thoughtful timing, and a light touch of scripting, you’ll deliver forms that guide rather than punish—leading to higher completion rates and fewer support tickets.