← thecodex.expert · The Codex Family of Knowledge
The Codex / JavaScript / Forms & Validation

Forms & Validation

Handling HTML forms with JavaScript — FormData, Constraint Validation API, custom validators, and controlled vs uncontrolled inputs.

What it is, in plain English: HTML forms let users submit data. JavaScript enhances them: you can prevent the default submission, read values with FormData, validate on the client using the Constraint Validation API (built into HTML), add custom validation logic, and show helpful error messages. Client-side validation is for user experience — always validate again on the server.
Where this bites you

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 gone

Intercepting 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()
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.