Forms & Validation
Handling HTML forms with JavaScript — FormData, Constraint Validation API, custom validators, and controlled vs uncontrolled inputs.
Object.fromEntries(new FormData(form)) is a popular one-liner, but it keeps only one value per name. With a group of checkboxes that share a name, every ticked box except the last is silently dropped. Unticked checkboxes aren't in the FormData at all, so a field such as newsletter is simply missing rather than false.
// <form id="signup">: an email field, and three "tags" checkboxes with js and ts ticked
const form = document.getElementById("signup");
const data = new FormData(form);
console.log(Object.fromEntries(data)); // looks like a neat shortcut...
// { email: "asha@example.com", tags: "ts" } <- "js" is goneIntercepting form submissions and reading values
The submit event — take control of form submission
const form = document.getElementById("signup");
form.addEventListener("submit", (event) => {
event.preventDefault(); // stop the page from reloading (default behaviour)
// Read values by name:
const email = form.querySelector('[name="email"]').value;
const password = form.querySelector('[name="password"]').value;
// Or use FormData — easier for multiple fields:
const data = new FormData(form);
console.log("Email:", data.get("email"));
console.log("Password:", data.get("password"));
console.log("All data:", Object.fromEntries(data)); // → plain object
});Object.fromEntries(data) in the example above is fine for forms where every name appears once. For repeated names, read them with getAll(), which returns every value as an array. Turn checkboxes into true/false yourself with has():
const form = document.getElementById("signup");
const data = new FormData(form);
const values = Object.fromEntries(data);
values.tags = data.getAll("tags"); // every checked box, as an array
values.newsletter = data.has("newsletter"); // unchecked boxes aren't in FormData at all
console.log(values);
// { email: "asha@example.com", tags: ["js", "ts"], newsletter: false }HTML5 built-in validation (Constraint Validation API)
<!-- HTML attributes trigger automatic validation: -->
<input type="email" required> <!-- must be a valid email -->
<input type="number" min="0" max="100"> <!-- 0-100 only -->
<input type="text" minlength="3" maxlength="50">
<input type="text" pattern="[A-Z]{3}-\d{4}"> <!-- regex pattern -->
<input type="url" required> <!-- must be a URL -->// Check validity in JavaScript:
const emailInput = document.querySelector('[name="email"]');
// Check if valid:
console.log(emailInput.checkValidity()); // true/false
// Get validation details:
const v = emailInput.validity;
console.log(v.valueMissing); // required field is empty
console.log(v.typeMismatch); // wrong type (e.g. not an email)
console.log(v.patternMismatch); // doesn't match pattern attribute
console.log(v.tooShort); // below minlength
// Show the browser's built-in error bubble:
emailInput.reportValidity();Custom validation messages
const emailInput = document.querySelector('[name="email"]');
emailInput.addEventListener("input", () => {
const email = emailInput.value;
if (!email.includes("@")) {
emailInput.setCustomValidity("Please include an @ symbol");
} else if (!email.includes(".")) {
emailInput.setCustomValidity("Email must have a domain (like .com)");
} else {
emailInput.setCustomValidity(""); // empty string = valid
}
});
// Custom error message shows in the browser tooltip on reportValidity()Official Sources
- MDN Web Docs — HTMLFormElement
- MDN Web Docs — FormData
- MDN Web Docs — Constraint validation
- MDN Web Docs — ValidityState
The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.