Forms & Validation
Collect and validate user input. The most common interactive pattern on the web.
Form Basics
Handle form submission with JavaScript.
// HTML:
// <form id="signup">
// <input name="email" type="email" required>
// <input name="password" type="password" required>
// <button type="submit">Sign Up</button>
// </form>
const form = document.getElementById("signup");
form.addEventListener("submit", (e) => {
e.preventDefault(); // stop page reload!
// Get values:
const email = form.elements.email.value;
const password = form.elements.password.value;
// Do something:
console.log("Signing up:", email);
});💡 Always call e.preventDefault() in the submit handler — otherwise the browser reloads the page (default form behavior).
Reading Values
Get data from different input types.
// Text, email, password, number:
input.value; // string (always a string!)
Number(input.value); // convert to number
// Checkbox:
checkbox.checked; // true/false
// Radio buttons:
const selected = form.querySelector('input[name="color"]:checked');
selected?.value; // value of selected radio
// Select (dropdown):
select.value; // selected option's value
select.selectedIndex; // index of selected option
select.options[select.selectedIndex].text; // display text
// Multiple select:
const selected = [...select.selectedOptions].map(o => o.value);
// Textarea:
textarea.value; // text content
// File input:
fileInput.files; // FileList
fileInput.files[0]; // first File objectFormData API
Get all form values at once — the modern way.
form.addEventListener("submit", (e) => {
e.preventDefault();
// Grab ALL form values in one line:
const formData = new FormData(form);
// Read individual fields:
formData.get("email"); // "user@test.com"
formData.get("password"); // "secret123"
// Convert to a plain object:
const data = Object.fromEntries(formData);
// { email: "user@test.com", password: "secret123" }
// Send to API:
fetch("/api/signup", {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" }
});
});// FormData methods:
formData.get("field"); // get value
formData.getAll("tags"); // get all values (multi-select)
formData.has("field"); // check if exists
formData.set("field", "new value"); // set/overwrite
formData.append("tags", "new"); // add another value
formData.delete("field"); // remove
// Iterate all entries:
for (const [key, value] of formData) {
console.log(key, value);
}
// Send FormData directly (for file uploads):
fetch("/api/upload", {
method: "POST",
body: formData, // Content-Type set automatically!
});Validation
Built-in HTML validation + Constraint Validation API.
// HTML validation attributes:
// <input type="email" required>
// <input type="number" min="0" max="100">
// <input minlength="8" maxlength="50">
// <input pattern="[A-Za-z]{3,}">
// Check validity with JavaScript:
const input = document.querySelector("input");
input.validity.valid; // true/false (overall)
input.validity.valueMissing; // true if required + empty
input.validity.typeMismatch; // true if wrong type (email)
input.validity.tooShort; // true if < minlength
input.validity.tooLong; // true if > maxlength
input.validity.patternMismatch; // true if doesn't match pattern
input.validity.rangeUnderflow; // true if < min
input.validity.rangeOverflow; // true if > max
// Check entire form:
form.checkValidity(); // true if all fields valid
form.reportValidity(); // show validation UICustom Validation
Build your own validation logic.
// Custom validation messages:
const email = document.querySelector("#email");
email.addEventListener("input", () => {
if (email.validity.typeMismatch) {
email.setCustomValidity("Please enter a valid email");
} else {
email.setCustomValidity(""); // clear = valid
}
});
// Full custom validation pattern:
form.addEventListener("submit", (e) => {
e.preventDefault();
const errors = validateForm(form);
if (errors.length > 0) {
showErrors(errors);
return;
}
submitForm(form);
});
function validateForm(form) {
const errors = [];
const data = Object.fromEntries(new FormData(form));
if (!data.email.includes("@")) {
errors.push({ field: "email", message: "Invalid email" });
}
if (data.password.length < 8) {
errors.push({ field: "password", message: "Min 8 characters" });
}
if (data.password !== data.confirmPassword) {
errors.push({ field: "confirmPassword", message: "Passwords don't match" });
}
return errors;
}// Real-time validation (as user types):
const passwordInput = document.querySelector("#password");
const feedback = document.querySelector("#password-feedback");
passwordInput.addEventListener("input", () => {
const val = passwordInput.value;
const checks = [
{ test: val.length >= 8, msg: "8+ characters" },
{ test: /[A-Z]/.test(val), msg: "Uppercase letter" },
{ test: /[0-9]/.test(val), msg: "Number" },
{ test: /[^A-Za-z0-9]/.test(val), msg: "Special character" },
];
feedback.innerHTML = checks
.map(c => `<span class="${c.test ? 'valid' : 'invalid'}">${c.msg}</span>`)
.join("");
});FAQ
Common questions about forms.