How to use regular expressions for form validation in JavaScript and HTML — with reusable patterns and common mistakes to avoid.
<!-- Username: 3-20 chars, letters/numbers/underscore -->
<input type="text" pattern="[a-zA-Z0-9_]{3,20}" required />
<!-- US ZIP code -->
<input type="text" pattern="\d{5}(-\d{4})?" required />
Add a title attribute to explain requirements to the user.
function validate(value, pattern) {
return pattern.test(value.trim());
}
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
validate("user@example.com", emailPattern); // true
validate("not-an-email", emailPattern); // false
Check each requirement separately for better UX:
const rules = {
minLength: (p) => p.length >= 8,
hasUppercase: (p) => /[A-Z]/.test(p),
hasLowercase: (p) => /[a-z]/.test(p),
hasDigit: (p) => /\d/.test(p),
hasSpecial: (p) => /[^a-zA-Z0-9]/.test(p),
};
Showing per-rule feedback is far better UX than a single error message.
const input = document.querySelector("#email");
input.addEventListener('blur', () => {
const valid = emailPattern.test(input.value);
input.setAttribute("aria-invalid", String(!valid));
});
Validate on blur, not on every keystroke — it's less annoying.
| Mistake | Problem | Fix |
|---|---|---|
| No anchors | Matches anywhere in string | Use ^...$ |
| Too strict email | Rejects valid addresses | Use simple pattern |
| Client-side only | Bypassable | Always validate server-side too |
Test your patterns with the Regex Tester.