18 minLesson 19 of 35
DOM & Browser APIs
Forms: Validation & Submission
Forms: Validation & Submission
Forms are how users send data to your application. JavaScript lets you validate input before submission, build rich interactive forms, and handle submission without page reloads.
Reading Form Data
const form = document.querySelector("#signup-form");
const email = document.querySelector("#email");
// Read individual values
email.value; // current text
email.type; // "email"
email.name; // "email" (name attribute)
email.placeholder; // "Enter your email"
email.required; // true/false
email.disabled; // true/false
// Checkboxes and radio buttons use .checked
document.querySelector("#terms").checked; // true/false
// Select elements
const select = document.querySelector("#country");
select.value; // selected value
select.selectedIndex; // index of selected option
select.options[select.selectedIndex].text; // display text
// Multiple select
const langs = document.querySelector("#languages[multiple]");
const selected = [...langs.options].filter(o => o.selected).map(o => o.value);
FormData Object
// Collect all form fields at once
form.addEventListener("submit", (e) => {
e.preventDefault();
const data = new FormData(form);
data.get("email"); // "alice@example.com"
data.get("username"); // "alice"
data.has("newsletter"); // true if checkbox was checked
// Convert to plain object
const obj = Object.fromEntries(data);
// { email: "alice@...", username: "alice", ... }
// For checkboxes that might be unchecked (not included in FormData):
const withDefaults = {
...Object.fromEntries(data),
newsletter: data.has("newsletter") // explicit boolean
};
});
HTML5 Validation
Browser-built-in validation is fast and accessible — use it before adding JavaScript:
<input type="email" required>
<input type="password" minlength="8" maxlength="50">
<input type="text" pattern="[A-Za-z0-9]+" title="Letters and numbers only">
<input type="number" min="0" max="100" step="5">
<input type="url" required>
// Check validity programmatically
const input = document.querySelector("#username");
input.validity.valid; // overall valid/invalid
input.validity.valueMissing; // required but empty
input.validity.tooShort; // shorter than minlength
input.validity.tooLong; // longer than maxlength
input.validity.patternMismatch; // doesn't match pattern
input.validity.typeMismatch; // wrong type (e.g., "abc" in email field)
input.validationMessage; // browser's error message
// Set a custom validation message
input.setCustomValidity("Username is already taken");
input.reportValidity(); // show the message
// Clear custom validity
input.setCustomValidity("");
Custom Validation Logic
function validateEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password) {
const errors = [];
if (password.length < 8) errors.push("Must be at least 8 characters");
if (!/[A-Z]/.test(password)) errors.push("Must contain uppercase letter");
if (!/[0-9]/.test(password)) errors.push("Must contain a number");
return errors;
}
function showError(input, message) {
const group = input.closest(".form-group");
const error = group.querySelector(".error-msg") || document.createElement("p");
error.className = "error-msg";
error.textContent = message;
error.style.color = "red";
if (!group.querySelector(".error-msg")) group.appendChild(error);
input.classList.add("error");
}
function clearError(input) {
const group = input.closest(".form-group");
group.querySelector(".error-msg")?.remove();
input.classList.remove("error");
}
Full Form Validation Example
const form = document.querySelector("#signup-form");
// Real-time validation as user types
form.querySelectorAll("input").forEach(input => {
input.addEventListener("blur", () => validateField(input));
input.addEventListener("input", () => clearError(input));
});
function validateField(input) {
const value = input.value.trim();
switch (input.name) {
case "username":
if (!value) return showError(input, "Username is required");
if (value.length < 3) return showError(input, "Must be at least 3 characters");
if (!/^[a-z0-9_]+$/i.test(value)) return showError(input, "Letters, numbers, underscores only");
break;
case "email":
if (!value) return showError(input, "Email is required");
if (!validateEmail(value)) return showError(input, "Enter a valid email");
break;
case "password":
if (!value) return showError(input, "Password is required");
const errors = validatePassword(value);
if (errors.length) return showError(input, errors[0]);
break;
case "confirm-password":
const password = form.querySelector("[name='password']").value;
if (value !== password) return showError(input, "Passwords must match");
break;
}
clearError(input);
return true;
}
form.addEventListener("submit", async (e) => {
e.preventDefault();
// Validate all fields
const inputs = [...form.querySelectorAll("input")];
const allValid = inputs.every(input => validateField(input));
if (!allValid) return;
// Submit
const submitBtn = form.querySelector("[type='submit']");
submitBtn.disabled = true;
submitBtn.textContent = "Creating account...";
try {
const data = Object.fromEntries(new FormData(form));
const res = await fetch("/api/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
if (!res.ok) {
const { message } = await res.json();
throw new Error(message);
}
form.innerHTML = `<p class="success">Account created! <a href="/login">Sign in</a></p>`;
} catch (err) {
showError(form, err.message);
} finally {
submitBtn.disabled = false;
submitBtn.textContent = "Create Account";
}
});
File Inputs
const fileInput = document.querySelector("#avatar");
fileInput.addEventListener("change", (e) => {
const file = e.target.files[0]; // FileList
if (!file) return;
// Validate
if (!file.type.startsWith("image/")) {
alert("Please select an image");
return;
}
if (file.size > 5 * 1024 * 1024) {
alert("Image must be under 5MB");
return;
}
// Preview
const reader = new FileReader();
reader.onload = (e) => {
document.querySelector("#preview").src = e.target.result;
};
reader.readAsDataURL(file);
// Upload with FormData
const formData = new FormData();
formData.append("avatar", file);
fetch("/api/upload", { method: "POST", body: formData });
});
Next lesson: Local Storage & Session Storage — persisting data in the browser.
📱
Get Notes Free →Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises