1. Introduction
Form validation ensures that user-submitted data meets expected rules (required fields, correct format, value ranges) before it is processed or sent to a server. There are two complementary approaches: declarative HTML5 constraint validation attributes, and imperative JavaScript validation logic for cases the built-in attributes cannot express.
Cricket analogy: Just as a match referee checks a bowler's run-up is within the marked crease (declarative rule set by the pitch) and also manually reviews a suspicious bowling action frame-by-frame (imperative judgment), form validation combines built-in HTML5 rules with custom JS checks before data is submitted.
Client-side validation improves user experience with immediate feedback, but it is never a substitute for server-side validation, since client-side checks can always be bypassed.
Cricket analogy: A batter shadow-practicing their shot at the crease before facing a real ball gives instant feedback, but the umpire's actual decision at the wicket is the real check -- client-side validation is like the shadow practice, never a substitute for server-side enforcement.
2. Syntax
<form id="signupForm" novalidate>
<input type="email" name="email" required placeholder="Email">
<input type="password" name="password" minlength="8" required placeholder="Password">
<input type="number" name="age" min="18" max="120">
<input type="text" name="username" pattern="[A-Za-z0-9_]{3,16}" required>
<button type="submit">Sign up</button>
</form>const form = document.getElementById('signupForm');
const email = form.elements.email;
// HTML5 built-in validation API
console.log(email.validity.valid); // boolean
console.log(email.validity.valueMissing); // true if required & empty
console.log(email.checkValidity()); // triggers validity check, returns boolean
// Custom JS validation on submit
form.addEventListener('submit', (event) => {
event.preventDefault(); // stop native submission/reload while we validate
if (!form.checkValidity()) {
form.reportValidity(); // show native error bubbles
return;
}
const password = form.elements.password.value;
if (password.toLowerCase() === password) {
email.setCustomValidity('Password must contain an uppercase letter');
form.reportValidity();
return;
}
email.setCustomValidity(''); // clear any previous custom error
console.log('Form is valid, submitting via fetch...');
});3. Explanation
HTML5 provides declarative constraint validation attributes such as required, minlength/maxlength, min/max, pattern, and input type (email, number, url, etc.). Browsers automatically enforce these when a form is submitted (unless novalidate is set on the <form>), showing native tooltip-style error messages and blocking submission.
Cricket analogy: HTML5's 'required' attribute is like a mandatory toss-coin rule that must happen before play begins, 'pattern' is like enforcing a legal bowling action shape, and browsers automatically block the 'match start' (submission) with a native warning tooltip unless the umpire waives the rule (novalidate).
JavaScript validation is needed for rules HTML5 attributes cannot express — cross-field comparisons (password confirmation matching), business logic (username availability via an API call), or custom messaging. The Constraint Validation API (element.validity, checkValidity(), reportValidity(), setCustomValidity()) lets JavaScript hook into and extend the native validation system rather than reimplementing it from scratch.
Cricket analogy: Checking that a bowler's declared pace matches their actual delivery speed on the radar gun (cross-field comparison) or verifying team-roster eligibility via a league database call (API business logic) needs custom JS, using setCustomValidity() like a referee adding a custom ruling note beyond the standard rulebook.
A common pattern is to call event.preventDefault() in the submit handler to stop the native page-reload submission, run checkValidity(), and only proceed (e.g., with a fetch call) if valid; native and custom validity messages can both be surfaced via reportValidity().
Cricket analogy: Just as an umpire holds up play with a raised hand (preventDefault) before checking all fielding positions are legal (checkValidity), and only signals play (proceeds with the fetch-equivalent next ball) if everything passes, announcing any issue over the PA (reportValidity).
Gotcha: Client-side validation (HTML5 attributes or JavaScript) is purely for user experience — it can be trivially bypassed by disabling JavaScript, editing DOM attributes in DevTools, or sending requests directly to the API. Server-side validation of all incoming data is mandatory for security and data integrity; never trust client-side checks alone.
4. Example
<form id="loginForm">
<input type="email" id="email" required>
<input type="password" id="pwd" minlength="8" required>
<span id="error"></span>
<button type="submit">Login</button>
</form>const form = document.getElementById('loginForm');
const errorSpan = document.getElementById('error');
form.addEventListener('submit', (e) => {
e.preventDefault();
errorSpan.textContent = '';
const emailInput = document.getElementById('email');
const pwdInput = document.getElementById('pwd');
if (!emailInput.validity.valid) {
errorSpan.textContent = 'Please enter a valid email address.';
return;
}
if (pwdInput.value.length < 8) {
errorSpan.textContent = 'Password must be at least 8 characters.';
return;
}
console.log('Validated -- submitting login for', emailInput.value);
});
// Simulate: user types "bademail" and password "123" then submits
emailInput.value = 'bademail';
pwdInput.value = '123';5. Output
On submit with email = 'bademail', password = '123':
1. e.preventDefault() stops the native page reload.
2. emailInput.validity.valid is false (type="email" requires an '@' and domain).
3. errorSpan text content becomes:
"Please enter a valid email address."
4. console.log('Validated -- submitting...') does NOT run.
If corrected to email = 'user@example.com', password = '123' (7 chars, too short):
errorSpan text becomes:
"Password must be at least 8 characters."
Only when both checks pass does the console print:
"Validated -- submitting login for user@example.com"6. Key Takeaways
- HTML5 attributes (required, pattern, min/max, minlength/maxlength, type) provide declarative validation for free.
- The Constraint Validation API (validity, checkValidity(), reportValidity(), setCustomValidity()) extends native validation from JS.
- event.preventDefault() in a submit handler stops the native page reload so custom JS validation/AJAX can run.
- Use JS validation for cross-field rules and business logic HTML5 attributes cannot express.
- Client-side validation is a UX convenience only — server-side validation is always required for security.
Practice what you learned
1. Which HTML attribute makes a browser automatically reject an empty input field on form submission?
2. What does form.checkValidity() do?
3. Why is client-side form validation alone insufficient for security?
4. What is the purpose of calling event.preventDefault() inside a form's submit handler?
5. Which Constraint Validation API method lets you set a custom error message for a field?
Was this page helpful?
You May Also Like
Event Handling in JavaScript
Learn how to listen for and respond to user interactions and browser events using addEventListener and the event object.
DOM Manipulation in JavaScript
Learn how to select, create, modify, and remove DOM elements using JavaScript, and the key differences between the main selector APIs.
Fetch API in JavaScript
Use the Fetch API to make HTTP requests, and learn the critical gotcha that fetch does not reject on HTTP error status codes.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics