JavaScript Tutorial menu

JavaScript Forms and Validation

Forms collect information from users. JavaScript reads that information, checks it, and gives quick feedback before anything is sent.

Reading Form Values

Each input has a value property. For checkboxes, use checked. A select box's value is the chosen option's value.

Example

html
<!DOCTYPE html>
<html>
<body>

<form id="order">
  <input name="customer" placeholder="Your name"><br><br>
  <select name="size">
    <option value="S">Small</option>
    <option value="M" selected>Medium</option>
    <option value="L">Large</option>
  </select>
  <label><input type="checkbox" name="gift"> Gift wrap</label><br><br>
  <button>Place order</button>
</form>
<p id="msg"></p>

<script>
const form = document.getElementById("order");

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const name = form.elements.customer.value;
  const size = form.elements.size.value;
  const gift = form.elements.gift.checked;
  document.getElementById("msg").textContent =
    `Thank you ${name}! Size: ${size}. Gift wrap: ${gift ? "yes" : "no"}.`;
});
</script>

</body>
</html>
Try it Yourself »

form.elements.customer finds the field with name="customer". The name attribute is the key to everything in forms.

FormData: All Fields at Once

new FormData(form) collects every named field. Object.fromEntries() turns it into a normal object, ready to send as JSON:

Example

javascript
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  const data = Object.fromEntries(new FormData(form));
  console.log(data);   // { customer: "Ali", size: "M", gift: "on" }

  await fetch("/api/orders", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data)
  });
});

An unchecked checkbox is simply missing from FormData, and a checked one has the value "on" (unless you give it a value).

Built-in HTML Validation

Before writing any JavaScript, use HTML attributes. The browser checks them for you when the form is submitted:

AttributeChecks
requiredThe field is not empty
type="email", type="url"The text looks like an email or link
minlength, maxlengthLength of the text
min, max, stepRange for numbers and dates
pattern="..."The value matches a regular expression

Example

html
<input name="phone" required pattern="03[0-9]{2}-?[0-9]{7}" title="Example: 0300-1234567">

The Constraint Validation API

JavaScript can read the result of those checks:

Property / MethodWhat it does
input.checkValidity()true if the field is valid
input.validityDetails: valueMissing, typeMismatch, tooShort, patternMismatch, rangeOverflow...
input.validationMessageThe browser's error text
input.setCustomValidity("msg")Marks the field invalid with your message. Pass "" to make it valid again
form.reportValidity()Checks all fields and shows the messages

Custom Messages and Live Feedback

This sign-up form uses HTML rules plus one custom rule (passwords must match), shows friendly messages under each field, and checks while the user types.

Example

html
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: sans-serif; padding: 16px; }
label { display: block; margin-top: 12px; }
input { padding: 6px; width: 240px; }
.error { color: #c0392b; font-size: 13px; min-height: 16px; }
input.invalid { border: 2px solid #c0392b; }
</style>
</head>
<body>

<form id="signup" novalidate>
  <label>Email <input name="email" type="email" required></label>
  <div class="error" id="email-error"></div>

  <label>Password <input name="password" type="password" required minlength="8"></label>
  <div class="error" id="password-error"></div>

  <label>Confirm password <input name="confirm" type="password" required></label>
  <div class="error" id="confirm-error"></div>

  <br><button>Create account</button>
</form>
<p id="done"></p>

<script>
const form = document.getElementById("signup");

function messageFor(input) {
  const v = input.validity;
  if (v.valueMissing) return "This field is required.";
  if (v.typeMismatch) return "Please enter a valid email, like ali@example.com.";
  if (v.tooShort) return "Use at least " + input.minLength + " characters.";
  if (v.customError) return input.validationMessage;
  return "";
}

function checkField(input) {
  if (input.name === "confirm") {
    const same = input.value === form.elements.password.value;
    input.setCustomValidity(same ? "" : "Passwords do not match.");
  }
  const msg = messageFor(input);
  document.getElementById(input.name + "-error").textContent = msg;
  input.classList.toggle("invalid", msg !== "");
  return msg === "";
}

form.addEventListener("input", (event) => {
  checkField(event.target);
  if (event.target.name === "password") checkField(form.elements.confirm);
});

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const fields = [...form.elements].filter(el => el.name);
  const allValid = fields.map(checkField).every(Boolean);
  document.getElementById("done").textContent = allValid ? "Account created!" : "";
});
</script>

</body>
</html>
Try it Yourself »

Some points to notice:

  • novalidate on the form turns off the browser's own pop-ups, so we can show our own messages. The rules still work through validity.
  • One input listener on the form handles every field, using event delegation.
  • fields.map(checkField) runs every check first, so all errors show at once, not only the first.

Front-end validation is for a better user experience only. Anyone can turn off JavaScript or send data directly to your server, so always validate again on the server.

Styling With CSS

CSS can react to validity too. :user-invalid matches a field only after the user has interacted with it, so empty forms do not start out red:

Example

css
input:user-invalid { border-color: crimson; }
input:valid { border-color: seagreen; }

Exercise

Exercise

Which method lets you mark a field as invalid with your own error message?

Learn JavaScript with a teacher

Join the Web Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp