Every web app has forms — login, signup, search, settings, creating content. In vanilla JavaScript, you handle forms by listening for the submit event, reading input values, and sending data to your backend.
// Text inputconst name = document.querySelector("#name").value; // "Sarah Chen"// Number inputconst age = Number(document.querySelector("#age").value); // 28// Checkboxconst agreed = document.querySelector("#terms").checked; // true or false// Radio buttonsconst selected = document.querySelector('input[name="plan"]:checked');const plan = selected ? selected.value : null; // "pro"// Select dropdownconst role = document.querySelector("#role").value; // "admin"// Textareaconst bio = document.querySelector("#bio").value; // "Full-stack developer..."
Input values are always strings, even from <input type="number">. Convert them with Number() when you need a number. The checked property on checkboxes is a boolean.
The standard pattern: listen for submit, prevent the default page reload, read values, and send to your API.
Copy
const form = document.querySelector("#create-user-form");form.addEventListener("submit", async (e) => { e.preventDefault(); // Don't reload the page! const formData = new FormData(form); const userData = Object.fromEntries(formData); try { const response = await fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(userData), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const newUser = await response.json(); console.log("Created:", newUser); form.reset(); // Clear the form } catch (error) { console.error("Failed to create user:", error); }});
e.preventDefault() is required. Without it, the browser submits the form the old-fashioned way — a full page reload with form data in the URL. You’ll lose your application state. This is the most common form handling mistake.
Without e.preventDefault(), the browser handles the form submission itself — reloading the page and appending form data to the URL. Your JavaScript fetch never completes.
Reading values at load time instead of submit time
Copy
// ❌ Wrong: reads value when page loads (empty)const nameInput = document.querySelector("#name");const name = nameInput.value; // "" — user hasn't typed yetform.addEventListener("submit", (e) => { e.preventDefault(); console.log(name); // Always "" — captured the initial empty value});// ✅ Correct: read value when form is submittedform.addEventListener("submit", (e) => { e.preventDefault(); const name = document.querySelector("#name").value; // Current value console.log(name); // "Sarah Chen" — whatever the user typed});
Missing name attributes on inputs
Copy
<!-- ❌ FormData can't read inputs without name attributes --><input id="username" type="text"><!-- ✅ Add name attribute --><input id="username" name="username" type="text">
FormData uses the name attribute, not id. If your inputs don’t have name, Object.fromEntries(new FormData(form)) will return an empty object.