DocsHub
DOM

Forms

Learn how to handle form input, validation, and submission using JavaScript and the DOM.

Forms

Forms are how users send data to your application — login credentials, search queries, contact messages, settings. JavaScript gives you full control over every part of a form — reading values, validating input, and handling submission.


The HTML We Will Use

<form id="signup-form">
  <input type="text" id="username" placeholder="Username">
  <input type="email" id="email" placeholder="Email">
  <input type="password" id="password" placeholder="Password">

  <select id="role">
    <option value="">Select a role</option>
    <option value="student">Student</option>
    <option value="developer">Developer</option>
    <option value="designer">Designer</option>
  </select>

  <textarea id="bio" placeholder="Short bio..."></textarea>

  <label>
    <input type="checkbox" id="terms"> I agree to the terms
  </label>

  <button type="submit">Sign Up</button>
</form>

Reading Form Values

Every form element has a value property that holds its current value.

const username = document.getElementById("username");
const email = document.getElementById("email");
const role = document.getElementById("role");
const bio = document.getElementById("bio");
const terms = document.getElementById("terms");

// Text inputs, email, password, textarea — use .value
console.log(username.value); // whatever the user typed
console.log(email.value);    // email@example.com
console.log(bio.value);      // multi-line text

// Select — .value gives the selected option's value
console.log(role.value); // "student", "developer", or "designer"

// Checkbox — use .checked, not .value
console.log(terms.checked); // true or false

Radio buttons

Radio buttons are grouped by name. Check .checked on each one or loop through them:

const radios = document.querySelectorAll('input[name="gender"]');
let selected;

for (const radio of radios) {
  if (radio.checked) {
    selected = radio.value;
    break;
  }
}

console.log(selected); // "male", "female", etc.

Handling Form Submission

Listen for the submit event on the form — not a click on the button. The submit event fires when the form is submitted by any means — button click, pressing Enter in an input.

Always call event.preventDefault() to stop the page from refreshing.

const form = document.getElementById("signup-form");

form.addEventListener("submit", (e) => {
  e.preventDefault(); // stop page refresh

  const data = {
    username: document.getElementById("username").value.trim(),
    email: document.getElementById("email").value.trim(),
    password: document.getElementById("password").value,
    role: document.getElementById("role").value,
    bio: document.getElementById("bio").value.trim(),
    terms: document.getElementById("terms").checked
  };

  console.log(data);
  // { username: "ali_dev", email: "ali@example.com", ... }
});

Using FormData

FormData is a built-in object that collects all form values automatically — no need to select each input manually. Every input needs a name attribute for this to work.

<form id="signup-form">
  <input type="text" name="username" placeholder="Username">
  <input type="email" name="email" placeholder="Email">
  <input type="password" name="password" placeholder="Password">
  <button type="submit">Sign Up</button>
</form>
form.addEventListener("submit", (e) => {
  e.preventDefault();

  const formData = new FormData(form);

  // Get a single value
  console.log(formData.get("username")); // "ali_dev"
  console.log(formData.get("email"));    // "ali@example.com"

  // Convert to a plain object
  const data = Object.fromEntries(formData);
  console.log(data);
  // { username: "ali_dev", email: "ali@example.com", password: "..." }
});

Object.fromEntries(formData) turns all form fields into a clean object in one line. This is the most efficient way to collect form data.


Listening to Input Changes

React to user input as it happens — not just on submit.

const usernameInput = document.getElementById("username");

// Fires on every keystroke
usernameInput.addEventListener("input", (e) => {
  console.log(e.target.value); // current value as user types
});

// Fires when input loses focus
usernameInput.addEventListener("blur", () => {
  validateUsername(usernameInput.value);
});

// Fires when value changes and element loses focus
usernameInput.addEventListener("change", (e) => {
  console.log("Final value:", e.target.value);
});

Use input for live feedback as the user types. Use blur for validation when they leave a field. Use change for select dropdowns and checkboxes.


Form Validation

Validating input before submission is one of the most important jobs JavaScript does with forms.

Manual validation

function validateForm(data) {
  const errors = {};

  if (!data.username) {
    errors.username = "Username is required.";
  } else if (data.username.length < 3) {
    errors.username = "Username must be at least 3 characters.";
  } else if (data.username.includes(" ")) {
    errors.username = "Username cannot contain spaces.";
  }

  if (!data.email) {
    errors.email = "Email is required.";
  } else if (!data.email.includes("@")) {
    errors.email = "Please enter a valid email.";
  }

  if (!data.password) {
    errors.password = "Password is required.";
  } else if (data.password.length < 8) {
    errors.password = "Password must be at least 8 characters.";
  }

  if (!data.role) {
    errors.role = "Please select a role.";
  }

  if (!data.terms) {
    errors.terms = "You must agree to the terms.";
  }

  return errors;
}

Showing errors in the UI

function showErrors(errors) {
  // Clear previous errors
  document.querySelectorAll(".error-message").forEach(el => el.remove());
  document.querySelectorAll(".input-error").forEach(el => {
    el.classList.remove("input-error");
  });

  // Show new errors
  for (const [field, message] of Object.entries(errors)) {
    const input = document.getElementById(field);
    if (!input) continue;

    input.classList.add("input-error");

    const errorEl = document.createElement("span");
    errorEl.className = "error-message";
    errorEl.textContent = message;

    input.insertAdjacentElement("afterend", errorEl);
  }
}

Putting it together

form.addEventListener("submit", (e) => {
  e.preventDefault();

  const data = Object.fromEntries(new FormData(form));
  data.terms = document.getElementById("terms").checked;

  const errors = validateForm(data);

  if (Object.keys(errors).length > 0) {
    showErrors(errors);
    return; // stop — do not submit
  }

  // No errors — proceed
  console.log("Form is valid. Submitting...", data);
  submitForm(data);
});

Live Validation — Validating as User Types

Better UX means validating each field as the user interacts with it — not all at once on submit.

const usernameInput = document.getElementById("username");
const emailInput = document.getElementById("email");
const passwordInput = document.getElementById("password");

function showFieldError(input, message) {
  clearFieldError(input);
  input.classList.add("input-error");

  const error = document.createElement("span");
  error.className = "error-message";
  error.textContent = message;
  input.insertAdjacentElement("afterend", error);
}

function clearFieldError(input) {
  input.classList.remove("input-error");
  const existing = input.nextElementSibling;
  if (existing?.classList.contains("error-message")) {
    existing.remove();
  }
}

function showFieldSuccess(input) {
  clearFieldError(input);
  input.classList.add("input-success");
}

// Validate username on blur
usernameInput.addEventListener("blur", () => {
  const value = usernameInput.value.trim();

  if (!value) {
    showFieldError(usernameInput, "Username is required.");
  } else if (value.length < 3) {
    showFieldError(usernameInput, "At least 3 characters.");
  } else {
    showFieldSuccess(usernameInput);
  }
});

// Live password strength indicator
passwordInput.addEventListener("input", () => {
  const value = passwordInput.value;
  const strength = value.length >= 12 ? "Strong"
                 : value.length >= 8  ? "Medium"
                 : "Weak";

  let indicator = document.getElementById("pwd-strength");
  if (!indicator) {
    indicator = document.createElement("span");
    indicator.id = "pwd-strength";
    passwordInput.insertAdjacentElement("afterend", indicator);
  }

  indicator.textContent = `Strength: ${strength}`;
  indicator.className = strength.toLowerCase();
});

Resetting a Form

// Reset all fields to their default values
form.reset();

// Or reset programmatically after submission
form.addEventListener("submit", (e) => {
  e.preventDefault();
  // ... handle submission
  form.reset();
  console.log("Form cleared.");
});

Disabling and Enabling Inputs

const submitBtn = document.querySelector('button[type="submit"]');
const inputs = form.querySelectorAll("input, select, textarea");

// Disable everything while submitting
function setFormLoading(loading) {
  submitBtn.disabled = loading;
  submitBtn.textContent = loading ? "Submitting..." : "Sign Up";

  inputs.forEach(input => {
    input.disabled = loading;
  });
}

A Real Example — Complete Signup Form

const form = document.getElementById("signup-form");

form.addEventListener("submit", async (e) => {
  e.preventDefault();

  // Collect data
  const formData = new FormData(form);
  const data = Object.fromEntries(formData);
  data.terms = document.getElementById("terms").checked;

  // Validate
  const errors = validateForm(data);
  if (Object.keys(errors).length > 0) {
    showErrors(errors);
    return;
  }

  // Show loading state
  setFormLoading(true);

  try {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1500));

    console.log("Account created!", data);

    // Show success message
    form.innerHTML = `
      <div class="success">
        <h2>Welcome, ${data.username}!</h2>
        <p>Your account has been created successfully.</p>
      </div>
    `;
  } catch (error) {
    console.error("Submission failed:", error);
    setFormLoading(false);
  }
});

The async/await syntax used here is covered in full detail in the Async JavaScript section. For now just know it handles operations that take time — like sending data to a server.


Summary

  • Listen for submit on the form — not click on the button
  • Always call e.preventDefault() to stop page refresh
  • Read input values with .value — checkboxes use .checked
  • FormData + Object.fromEntries() collects all form values in one line
  • Use input event for live feedback, blur for field validation, change for selects
  • Validate before submitting — return early if errors exist
  • Show errors next to the relevant fields, clear them when the user corrects input
  • Disable the form during submission to prevent double submits
  • form.reset() clears all fields back to their default values

On this page