JavaScript form validation checks user input before your website accepts or sends a form.
You can check whether required fields are empty, whether an email address has a valid format, whether a password meets your rules, or whether a user accepted required terms.
Good form validation should help users fix mistakes clearly. It should not make forms harder to complete.
Course Home: JavaScript Tutorial for Beginners
Previous Lesson: JavaScript Events Explained
Next Lesson: JavaScript Fetch API Explained
Quick Answer
A common JavaScript form-validation pattern is:
<form id="signupForm">
<label for="email">Email</label>
<input id="email" type="email">
<p id="emailError"></p>
<button type="submit">Sign Up</button>
</form>
const signupForm = document.querySelector("#signupForm");
const email = document.querySelector("#email");
const emailError = document.querySelector("#emailError");
signupForm.addEventListener("submit", (event) => {
if (email.value.trim() === "") {
event.preventDefault();
emailError.textContent = "Email is required";
}
});
The form listens for the submit event.
If the email is empty, JavaScript:
- Stops the submission.
- Shows an error message.
- Lets the user correct the field.
For important forms, client-side validation should also be repeated on the server. Browser JavaScript can improve the user experience, but users can bypass it.
What Is Form Validation in JavaScript?
Form validation checks whether user input meets the rules your form requires.
For example, a signup form may require:
- A name
- An email address
- A password
- A minimum password length
- Agreement to terms
A checkout form may require:
- Delivery address
- City
- Postal code
- Phone number
- Payment-related information
JavaScript can read the current values and decide whether the form is ready to continue.
Why Form Validation Matters
Validation helps prevent incomplete or clearly incorrect form submissions.
It can also give users immediate feedback.
For example:
Email is required
is more useful than submitting the form and showing a vague error later.
Useful validation can:
- Point to the field that needs attention
- Explain what is wrong
- Keep valid user input in place
- Reduce avoidable submission errors
- Improve form completion
- Help users correct mistakes before sending data
Validation should be clear, specific, and easy to recover from.
HTML Validation Comes First
Before writing JavaScript, use the validation features already available in HTML.
Example:
<form>
<label for="email">Email</label>
<input
id="email"
name="email"
type="email"
required
>
<button type="submit">Submit</button>
</form>
This uses:
type="email"
required
The browser can already check whether the field is empty and whether the value resembles an email address.
JavaScript should enhance useful HTML validation rather than replace it without reason.
Useful HTML Validation Attributes
Common attributes include:
| Attribute | Purpose |
|---|---|
required | Field must contain a value |
minlength | Minimum text length |
maxlength | Maximum text length |
min | Minimum numeric or date value |
max | Maximum numeric or date value |
pattern | Value must match a pattern |
type="email" | Email-format validation |
type="url" | URL-format validation |
Example:
<input
id="password"
type="password"
required
minlength="8"
>
The browser now knows the password field is required and needs at least eight characters.
JavaScript Validation and HTML Validation Work Together
You might use HTML for basic rules:
<input
id="email"
type="email"
required
>
Then use JavaScript for custom feedback:
if (email.value.trim() === "") {
emailError.textContent = "Enter your email address";
}
This gives you more control over how errors appear while keeping useful browser behavior.
Basic Form Setup
Use this form for the first examples:
<form id="signupForm" novalidate>
<div>
<label for="name">Name</label>
<input id="name" name="name" type="text">
<p id="nameError"></p>
</div>
<div>
<label for="email">Email</label>
<input id="email" name="email" type="email">
<p id="emailError"></p>
</div>
<button type="submit">Sign Up</button>
</form>
The novalidate attribute disables the browser’s default validation messages for this example.
That lets JavaScript display custom messages.
Do not add novalidate automatically to every real form. Use it only when your JavaScript provides a complete and accessible validation experience.
Listen for the Form submit Event
Select the form:
const signupForm = document.querySelector("#signupForm");
Then listen for submission:
signupForm.addEventListener("submit", (event) => {
console.log("Form submitted");
});
Use the form’s submit event rather than relying only on a button click.
A form can also be submitted through keyboard actions such as pressing Enter.
You learned this behavior in the JavaScript Events tutorial.
Stop Submission When Validation Fails
Use:
event.preventDefault();
when your JavaScript finds an error.
Example:
signupForm.addEventListener("submit", (event) => {
if (email.value.trim() === "") {
event.preventDefault();
}
});
Do not prevent submission automatically before you know whether the form is valid unless your application intentionally handles the entire submission process with JavaScript.
Validate a Required Text Field
HTML:
<label for="name">Name</label>
<input id="name" type="text">
<p id="nameError"></p>
JavaScript:
const nameInput = document.querySelector("#name");
const nameError = document.querySelector("#nameError");
function validateName() {
const name = nameInput.value.trim();
if (name === "") {
nameError.textContent = "Name is required";
return false;
}
nameError.textContent = "";
return true;
}
The function returns:
false
when validation fails.
It returns:
true
when the name is acceptable.
Why Use trim()?
A user could enter only spaces:
" "
Without trim(), that string is not empty.
Example:
const value = " ";
console.log(value === "");
Output:
false
But:
console.log(value.trim() === "");
Output:
true
For many required text fields, trimming before the empty check is useful.
Validate an Email Field
HTML:
<label for="email">Email</label>
<input
id="email"
type="email"
>
<p id="emailError"></p>
JavaScript:
const emailInput = document.querySelector("#email");
const emailError = document.querySelector("#emailError");
function validateEmail() {
const email = emailInput.value.trim();
if (email === "") {
emailError.textContent = "Email is required";
return false;
}
if (!emailInput.validity.valid) {
emailError.textContent = "Enter a valid email address";
return false;
}
emailError.textContent = "";
return true;
}
This uses the browser’s built-in email validity check instead of trying to create a complicated email regular expression.
Why Avoid Overly Complex Email Regex?
Email-address rules are more complicated than they appear.
A large custom regular expression can reject valid addresses or accept values you did not expect.
For normal browser forms, this is often a better starting point:
<input type="email">
Then JavaScript can inspect the field’s validity.
Validation checks whether the format is acceptable for the form. It does not prove that the email address exists or belongs to the user.
Email ownership normally requires a verification process such as sending a confirmation message.
The validity Property
Form controls expose a:
validity
property.
Example:
console.log(emailInput.validity.valid);
This returns:
true
or:
false
depending on whether the field satisfies its active HTML constraints.
The validity object contains more detailed flags.
Common ValidityState Properties
Useful properties include:
valid
valueMissing
typeMismatch
tooShort
tooLong
rangeUnderflow
rangeOverflow
patternMismatch
customError
Example:
if (emailInput.validity.valueMissing) {
console.log("Email is missing");
}
Another:
if (emailInput.validity.typeMismatch) {
console.log("Email format is invalid");
}
These checks can help you show a more specific message.
Use required With the Constraint Validation API
HTML:
<input
id="email"
type="email"
required
>
JavaScript:
if (emailInput.validity.valueMissing) {
emailError.textContent = "Email is required";
} else if (emailInput.validity.typeMismatch) {
emailError.textContent = "Enter a valid email address";
}
This combines HTML constraints with custom JavaScript feedback.
checkValidity()
You can ask whether a form control currently satisfies its constraints:
const isValid = emailInput.checkValidity();
console.log(isValid);
The result is a boolean.
You can also call:
form.checkValidity();
to check all controls participating in constraint validation.
reportValidity()
reportValidity() checks constraints and can also ask the browser to display its validation UI.
Example:
if (!signupForm.reportValidity()) {
console.log("Form has validation errors");
}
Use this when you want native browser feedback.
If you provide fully custom error messages, you may use your own validation flow instead.
setCustomValidity()
You can give a field a custom validation error.
Example:
const username = document.querySelector("#username");
username.setCustomValidity("This username is not available");
The field now fails constraint validation.
Clear the custom error when the issue is resolved:
username.setCustomValidity("");
An empty string removes the custom validity error.
Real Website Example: Matching Passwords
HTML:
<label for="password">Password</label>
<input id="password" type="password">
<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" type="password">
<p id="passwordError"></p>
JavaScript:
const password = document.querySelector("#password");
const confirmPassword = document.querySelector("#confirmPassword");
const passwordError = document.querySelector("#passwordError");
function validatePasswordMatch() {
if (password.value !== confirmPassword.value) {
passwordError.textContent = "Passwords do not match";
return false;
}
passwordError.textContent = "";
return true;
}
This is a practical example of comparing two form values.
Validate Password Length
Suppose your form requires at least eight characters.
HTML:
<input
id="password"
type="password"
minlength="8"
required
>
JavaScript:
function validatePassword() {
if (password.validity.valueMissing) {
passwordError.textContent = "Password is required";
return false;
}
if (password.validity.tooShort) {
passwordError.textContent =
"Password must contain at least 8 characters";
return false;
}
passwordError.textContent = "";
return true;
}
Keep password requirements clear and visible before submission rather than revealing them only after an error.
Do Not Treat Frontend Password Rules as Security
Client-side validation can check whether a password meets your interface rules.
It cannot safely enforce account security by itself.
The server must validate and process passwords securely.
Never trust browser JavaScript as your only security control.
Validate a Checkbox
HTML:
<label>
<input id="terms" type="checkbox">
I accept the terms
</label>
<p id="termsError"></p>
JavaScript:
const terms = document.querySelector("#terms");
const termsError = document.querySelector("#termsError");
function validateTerms() {
if (!terms.checked) {
termsError.textContent = "Accept the terms to continue";
return false;
}
termsError.textContent = "";
return true;
}
Checkboxes use:
checked
rather than the text value for a simple checked-state test.
HTML Can Validate a Required Checkbox
You can also use:
<input
id="terms"
type="checkbox"
required
>
Then:
terms.validity.valueMissing
will indicate whether the required checkbox is unchecked.
Validate a Select Menu
HTML:
<label for="country">Country</label>
<select id="country">
<option value="">Choose a country</option>
<option value="india">India</option>
<option value="usa">United States</option>
</select>
<p id="countryError"></p>
JavaScript:
const country = document.querySelector("#country");
const countryError = document.querySelector("#countryError");
function validateCountry() {
if (country.value === "") {
countryError.textContent = "Choose a country";
return false;
}
countryError.textContent = "";
return true;
}
The placeholder option uses an empty value so it is easy to identify.
Validate a Number Range
HTML:
<label for="quantity">Quantity</label>
<input
id="quantity"
type="number"
min="1"
max="5"
required
>
<p id="quantityError"></p>
JavaScript:
const quantity = document.querySelector("#quantity");
const quantityError = document.querySelector("#quantityError");
function validateQuantity() {
if (quantity.validity.valueMissing) {
quantityError.textContent = "Choose a quantity";
return false;
}
if (
quantity.validity.rangeUnderflow ||
quantity.validity.rangeOverflow
) {
quantityError.textContent =
"Quantity must be between 1 and 5";
return false;
}
quantityError.textContent = "";
return true;
}
Using min and max keeps the rules visible in the HTML.
Validate With pattern
HTML supports the pattern attribute for certain text-like inputs.
Example:
<input
id="pinCode"
type="text"
inputmode="numeric"
pattern="[0-9]{6}"
required
>
JavaScript can check:
pinCode.validity.patternMismatch
Use a pattern only when the rule is clear and appropriate for your users.
Do not force one format onto data that genuinely varies.
Real Website Example: Six-Digit PIN Code
const pinCode = document.querySelector("#pinCode");
const pinCodeError = document.querySelector("#pinCodeError");
function validatePinCode() {
if (pinCode.validity.valueMissing) {
pinCodeError.textContent = "PIN code is required";
return false;
}
if (pinCode.validity.patternMismatch) {
pinCodeError.textContent = "Enter a 6-digit PIN code";
return false;
}
pinCodeError.textContent = "";
return true;
}
This example uses the HTML pattern as the validation rule.
Combine Several Validation Functions
Suppose you have:
validateName()
validateEmail()
validatePassword()
validateTerms()
Your submit handler can run them:
signupForm.addEventListener("submit", (event) => {
const nameIsValid = validateName();
const emailIsValid = validateEmail();
const passwordIsValid = validatePassword();
const termsAreValid = validateTerms();
const formIsValid =
nameIsValid &&
emailIsValid &&
passwordIsValid &&
termsAreValid;
if (!formIsValid) {
event.preventDefault();
}
});
This keeps each field’s rules in a focused function.
Why Store Each Validation Result?
Do not write:
if (
!validateName() ||
!validateEmail() ||
!validatePassword()
) {
event.preventDefault();
}
when your validation functions need to run for every field.
Logical OR short-circuiting can stop after the first truthy failure condition.
Storing each result separately ensures every validation function runs.
That lets the page show all relevant errors at once.
You learned short-circuit behavior in the JavaScript Logical Operators tutorial.
Complete Basic Validation Example
HTML:
<form id="signupForm" novalidate>
<div>
<label for="name">Name</label>
<input
id="name"
name="name"
type="text"
required
>
<p id="nameError"></p>
</div>
<div>
<label for="email">Email</label>
<input
id="email"
name="email"
type="email"
required
>
<p id="emailError"></p>
</div>
<div>
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
minlength="8"
required
>
<p id="passwordError"></p>
</div>
<label>
<input
id="terms"
name="terms"
type="checkbox"
required
>
I accept the terms
</label>
<p id="termsError"></p>
<button type="submit">Create Account</button>
</form>
JavaScript:
const signupForm = document.querySelector("#signupForm");
const nameInput = document.querySelector("#name");
const emailInput = document.querySelector("#email");
const passwordInput = document.querySelector("#password");
const termsInput = document.querySelector("#terms");
const nameError = document.querySelector("#nameError");
const emailError = document.querySelector("#emailError");
const passwordError = document.querySelector("#passwordError");
const termsError = document.querySelector("#termsError");
function validateName() {
if (nameInput.value.trim() === "") {
nameError.textContent = "Name is required";
return false;
}
nameError.textContent = "";
return true;
}
function validateEmail() {
if (emailInput.validity.valueMissing) {
emailError.textContent = "Email is required";
return false;
}
if (emailInput.validity.typeMismatch) {
emailError.textContent = "Enter a valid email address";
return false;
}
emailError.textContent = "";
return true;
}
function validatePassword() {
if (passwordInput.validity.valueMissing) {
passwordError.textContent = "Password is required";
return false;
}
if (passwordInput.validity.tooShort) {
passwordError.textContent =
"Password must contain at least 8 characters";
return false;
}
passwordError.textContent = "";
return true;
}
function validateTerms() {
if (!termsInput.checked) {
termsError.textContent = "Accept the terms to continue";
return false;
}
termsError.textContent = "";
return true;
}
signupForm.addEventListener("submit", (event) => {
const nameIsValid = validateName();
const emailIsValid = validateEmail();
const passwordIsValid = validatePassword();
const termsAreValid = validateTerms();
const formIsValid =
nameIsValid &&
emailIsValid &&
passwordIsValid &&
termsAreValid;
if (!formIsValid) {
event.preventDefault();
}
});
This example validates all four fields before allowing normal form submission.
Validate While the User Types
You can also validate after an input event.
Example:
nameInput.addEventListener("input", () => {
validateName();
});
For email:
emailInput.addEventListener("input", () => {
validateEmail();
});
Real-time validation can help, but avoid showing aggressive errors before the user has had a reasonable chance to enter the value.
A common approach is:
- Validate on submit.
- After a field has shown an error, update that error while the user fixes it.
Validate on blur
You can check a field when the user leaves it:
emailInput.addEventListener("blur", () => {
validateEmail();
});
This can provide earlier feedback than waiting for submission.
However, validation timing should not create a distracting stream of error messages.
Clear an Error While the User Fixes It
Example:
emailInput.addEventListener("input", () => {
if (emailInput.validity.valid) {
emailError.textContent = "";
}
});
This removes the error once the field satisfies its current HTML constraints.
Add an Error Class
CSS:
.field-error {
border-color: currentColor;
}
JavaScript:
if (!emailInput.validity.valid) {
emailInput.classList.add("field-error");
}
Remove it when valid:
emailInput.classList.remove("field-error");
Do not communicate errors through color alone.
Always provide text explaining what needs to be fixed.
Add aria-invalid
For an invalid form control, you can set:
emailInput.setAttribute("aria-invalid", "true");
When the field becomes valid:
emailInput.removeAttribute("aria-invalid");
This can help assistive technology understand the current error state.
Use accessibility attributes accurately rather than adding them without updating their state.
Connect an Error Message With aria-describedby
HTML:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-describedby="emailError"
>
<p id="emailError"></p>
The aria-describedby relationship tells assistive technology that the error paragraph provides additional information about the field.
If the same element also contains persistent help text, keep that relationship useful even when no error is present.
Focus the First Invalid Field
When submission fails, moving focus to the first invalid field can help users find the problem.
Example:
signupForm.addEventListener("submit", (event) => {
if (!signupForm.checkValidity()) {
event.preventDefault();
const firstInvalidField =
signupForm.querySelector(":invalid");
firstInvalidField?.focus();
}
});
If you use novalidate, your own validation logic must correctly identify invalid controls.
Do not move focus repeatedly while the user is typing.
Use :invalid Carefully
CSS can target invalid form controls:
input:invalid {
border-color: currentColor;
}
But required fields may be considered invalid before the user interacts with them.
That can make a fresh form look full of errors.
Many interfaces add a class only after submission or after a field has been touched, then style invalid fields within that state.
Custom Validation Message Helper
If several fields need similar error handling, create a helper function.
function showError(input, errorElement, message) {
errorElement.textContent = message;
input.setAttribute("aria-invalid", "true");
}
And:
function clearError(input, errorElement) {
errorElement.textContent = "";
input.removeAttribute("aria-invalid");
}
Now your field functions can focus on validation rules.
Example:
function validateName() {
if (nameInput.value.trim() === "") {
showError(
nameInput,
nameError,
"Name is required"
);
return false;
}
clearError(nameInput, nameError);
return true;
}
This reduces repeated DOM code.
Validate Related Fields Together
Some rules involve more than one field.
A password confirmation is one example.
HTML:
<input id="password" type="password">
<input id="confirmPassword" type="password">
JavaScript:
function validatePasswordMatch() {
if (password.value !== confirmPassword.value) {
showError(
confirmPassword,
confirmPasswordError,
"Passwords do not match"
);
return false;
}
clearError(confirmPassword, confirmPasswordError);
return true;
}
The error belongs most naturally to the confirmation field because that is where the mismatch is being resolved.
Real Website Example: Contact Form
HTML:
<form id="contactForm" novalidate>
<label for="contactName">Name</label>
<input
id="contactName"
type="text"
required
>
<p id="contactNameError"></p>
<label for="contactEmail">Email</label>
<input
id="contactEmail"
type="email"
required
>
<p id="contactEmailError"></p>
<label for="message">Message</label>
<textarea
id="message"
minlength="20"
required
></textarea>
<p id="messageError"></p>
<button type="submit">Send Message</button>
</form>
The message field can be checked with:
function validateMessage() {
if (messageInput.validity.valueMissing) {
messageError.textContent = "Message is required";
return false;
}
if (messageInput.validity.tooShort) {
messageError.textContent =
"Message must contain at least 20 characters";
return false;
}
messageError.textContent = "";
return true;
}
The same validation structure can support many forms.
Real Website Example: Shopping Quantity
HTML:
<input
id="quantity"
type="number"
min="1"
max="10"
required
>
JavaScript:
function validateQuantity() {
if (!quantityInput.checkValidity()) {
quantityError.textContent =
"Choose a quantity from 1 to 10";
return false;
}
quantityError.textContent = "";
return true;
}
The browser handles the numeric range rules defined in HTML.
Real Website Example: Delivery Option
HTML:
<label>
<input
type="radio"
name="delivery"
value="standard"
>
Standard
</label>
<label>
<input
type="radio"
name="delivery"
value="express"
>
Express
</label>
<p id="deliveryError"></p>
JavaScript:
function validateDelivery() {
const selectedDelivery =
document.querySelector(
'input[name="delivery"]:checked'
);
if (!selectedDelivery) {
deliveryError.textContent =
"Choose a delivery option";
return false;
}
deliveryError.textContent = "";
return true;
}
The selector finds the checked radio button.
If none is selected, it returns null.
Read Form Values With FormData
The browser provides FormData for reading successful form controls.
HTML:
<form id="profileForm">
<input name="name" value="Riya">
<input name="city" value="Delhi">
</form>
JavaScript:
const profileForm = document.querySelector("#profileForm");
const formData = new FormData(profileForm);
console.log(formData.get("name"));
console.log(formData.get("city"));
Output:
Riya
Delhi
FormData becomes especially useful when you later send form data with the Fetch API.
Validate Before Creating FormData for Submission
A useful flow is:
form.addEventListener("submit", (event) => {
if (!form.checkValidity()) {
event.preventDefault();
return;
}
const formData = new FormData(form);
});
If JavaScript is sending the request itself, you will usually prevent the normal submission and then send the validated data.
You will learn that in the JavaScript Fetch API tutorial.
Never Trust Client-Side Validation Alone
This is one of the most important rules in form development.
JavaScript runs in the user’s browser.
A user can:
- Disable JavaScript
- Change the HTML
- Send a request manually
- Modify values before submission
- Bypass your interface completely
For this reason:
Client-side validation improves usability. Server-side validation protects your application and data.
Every important rule must be checked again on the server.
Client-Side vs Server-Side Validation
Client-side validation
Runs in the browser.
Useful for:
- Fast feedback
- Required-field messages
- Format guidance
- Range checks
- Better form usability
Server-side validation
Runs on your server.
Required for:
- Security
- Data integrity
- Authorization
- Business rules
- Trusted validation
- Safe database operations
A production application normally needs both.
Validation Is Not Sanitization
Validation checks whether data matches your rules.
For example:
Is this field empty?
Is this number between 1 and 5?
Does this email field have an acceptable format?
Sanitization and output encoding solve different problems.
Do not assume a value is safe to insert into HTML just because it passed a form validation rule.
When displaying user-provided text in the DOM, prefer:
textContent
instead of injecting untrusted strings with:
innerHTML
Review the JavaScript DOM Manipulation tutorial for this distinction.
Do Not Validate by Disabling Paste
Do not block paste in password, email, or confirmation fields simply to force manual typing.
Users may rely on password managers, clipboard tools, or accessibility workflows.
Validate the resulting value rather than restricting normal input methods without a strong reason.
Avoid Unclear Error Messages
Weak:
Invalid input
Better:
Enter your email address
Or:
Password must contain at least 8 characters
Error messages should tell the user what needs fixing.
Keep Error Messages Near the Field
Place field-specific errors close to the related control.
Example:
<label for="email">Email</label>
<input id="email" type="email">
<p id="emailError"></p>
This is easier to understand than placing every error only at the top of a long form.
For long forms, you may also provide an error summary that links users to each invalid field.
Do Not Clear User Input After Validation Fails
If a user enters a long form and one field is wrong, keep their valid values.
Do not reset the entire form simply because one field failed validation.
Make recovery easy.
Do Not Show Errors Before They Are Useful
A blank required field is technically invalid before the user enters anything.
But showing:
Name is required
the moment the page loads can feel like the form is already blaming the user.
Common validation timing options include:
- On submit
- On blur after interaction
- While editing a field that already has an error
Choose timing that helps rather than distracts.
Prevent Double Submission
After a valid JavaScript-controlled submission begins, you may temporarily disable the submit button.
Example:
submitButton.disabled = true;
Then restore it if the request fails:
submitButton.disabled = false;
Do this only when your JavaScript controls the asynchronous submission flow.
You will handle that properly after learning fetch() and async/await.
Common Beginner Mistakes
Validating Only the Submit Button Click
Avoid relying only on:
submitButton.addEventListener("click", validateForm);
Listen for:
form.addEventListener("submit", validateForm);
because the form can be submitted in other ways.
Calling preventDefault() Without Need
If the form is valid and should use normal browser submission, do not prevent it.
Use preventDefault() when validation fails or when JavaScript intentionally handles the submission.
Forgetting trim() on Required Text Fields
A string containing spaces can pass a simple:
value !== ""
check.
For many required text fields, use:
value.trim() !== ""
Using Only a Huge Email Regex
For standard browser forms, start with:
type="email"
and the browser’s constraint-validation tools.
Do not assume a complicated regular expression proves an email address is real.
Trusting Client-Side Validation for Security
Browser validation can be bypassed.
Validate important data again on the server.
Showing Errors With Color Only
A red border by itself does not explain the problem.
Add a clear text message.
Forgetting to Clear Old Errors
If a field becomes valid, remove its old error message.
Otherwise the page may show stale information.
Using innerHTML for User Input
Avoid:
message.innerHTML = userInput;
for untrusted form values.
Use:
message.textContent = userInput;
when displaying plain text.
Comparing Number Inputs as Strings Without Thinking
Input values are generally read as strings.
Example:
console.log(quantityInput.value);
may return:
"5"
For numeric logic, you can use:
quantityInput.valueAsNumber
with suitable number inputs.
Example:
const quantity = quantityInput.valueAsNumber;
Check for missing or invalid values before using the number.
Assuming required Handles Every Business Rule
required only tells you a value must be present.
It does not check every rule your application may need.
For example, a username may be syntactically valid but already taken.
That kind of rule may require a server request.
Showing All Errors Only at the End of the Page
Users should be able to connect an error to the field that needs correction.
Place field errors near the controls and use an error summary when helpful for long forms.
Resetting the Form After an Error
Do not erase valid input just because one field failed.
Blocking Submission Without Explaining Why
Every blocked submission should provide clear feedback.
The user should know what to fix.
Best Practices for JavaScript Form Validation
Use semantic HTML labels and native form controls.
Start with HTML validation attributes.
Use JavaScript for custom rules and clearer feedback.
Listen for the form’s submit event.
Use trim() for required free-text fields when surrounding spaces should not count.
Use validity, checkValidity(), and related browser APIs where they fit.
Return clear booleans from focused validation functions.
Keep field-specific validation in small functions.
Show errors close to the related fields.
Use text, not color alone, to explain errors.
Set aria-invalid accurately when providing custom validation states.
Keep valid user input after errors.
Focus the first invalid field after a failed submission when that improves usability.
Do not show errors too early.
Validate important data again on the server.
Do not treat validation as sanitization or security.
Beginner Exercise
Use this HTML:
<form id="loginForm" novalidate>
<label for="email">Email</label>
<input
id="email"
type="email"
required
>
<p id="emailError"></p>
<label for="password">Password</label>
<input
id="password"
type="password"
minlength="8"
required
>
<p id="passwordError"></p>
<button type="submit">Login</button>
</form>
Complete these tasks:
- Listen for the
submitevent. - Show
Email is requiredwhen email is empty. - Show
Enter a valid email addresswhen its format fails. - Show
Password is requiredwhen password is empty. - Show
Password must contain at least 8 characterswhen too short. - Prevent submission when either field is invalid.
- Clear each error after that field becomes valid.
Challenge Exercise
Create a signup form containing:
- Name
- Password
- Confirm password
- Terms checkbox
Validation rules:
- Name cannot be empty.
- Email must pass the browser’s email validation.
- Password must contain at least eight characters.
- Confirm password must match the password.
- Terms must be checked.
Create one validation function for each rule.
Run all validation functions on form submission.
Prevent submission when any rule fails.
Extra Challenge
Add:
aria-invalid
to invalid fields.
Remove it when each field becomes valid.
Then focus the first invalid field after a failed submission.
Frequently Asked Questions
What is JavaScript form validation?
JavaScript form validation checks user input against rules before or during form submission and can show custom feedback when values are missing or invalid.
Should I validate forms with HTML or JavaScript?
Use both where appropriate.
HTML provides useful native constraints such as required, type="email", minlength, min, max, and pattern.
JavaScript can add custom rules, custom messages, and dynamic behavior.
What is the submit event?
The submit event fires on a form when the form is submitted.
For validation, listen on the form:
form.addEventListener("submit", handleSubmit);
What does preventDefault() do in form validation?
It stops the form’s normal submission behavior when your JavaScript needs to keep the user on the page, such as after validation fails.
How do I check whether an input is empty?
For many text inputs:
input.value.trim() === ""
is a useful required-field check.
How do I validate an email in JavaScript?
For standard browser forms, use:
<input type="email">
and check the control’s validity.
Example:
emailInput.validity.valid
Do not rely on a complicated regular expression to prove an email address exists.
How do I validate a password length?
Use HTML:
minlength="8"
and JavaScript when you need custom messages.
You can inspect:
password.validity.tooShort
How do I check whether two passwords match?
Compare their values with strict equality:
password.value === confirmPassword.value
How do I validate a checkbox?
Check its:
checked
property.
Example:
if (!terms.checked) {
// show error
}
How do I validate a select menu?
Check its selected value.
Example:
if (country.value === "") {
// show error
}
What is the Constraint Validation API?
It is a browser API for working with form validation rules.
Useful features include:
validity
checkValidity()
reportValidity()
setCustomValidity()
What does checkValidity() do?
It checks whether an element or form satisfies its active HTML validation constraints and returns a boolean.
What does reportValidity() do?
It checks validity and can display the browser’s validation feedback when a control is invalid.
What does setCustomValidity() do?
It adds a custom validity error message to a form control.
Clear it with:
input.setCustomValidity("");
What is validity.valueMissing?
It becomes true when a required form control has no acceptable value.
What is validity.typeMismatch?
It can become true when a value does not match the input type, such as an invalid value in an email input.
What is validity.tooShort?
It indicates that a text value is shorter than its minlength requirement when the browser applies that constraint.
Is JavaScript form validation secure?
Not by itself.
Client-side validation can be bypassed.
Important rules must also be validated on the server.
Is validation the same as sanitization?
No.
Validation checks whether data follows rules.
Sanitization, safe output handling, and encoding address different concerns.
Should I use innerHTML to show form values?
Not for untrusted user input.
Use textContent when displaying plain user-provided text.
Should validation happen while the user types?
It can, but avoid showing aggressive errors too early.
A useful pattern is to validate on submit, then update existing errors while the user corrects the fields.
Should I disable the submit button until the form is valid?
Sometimes, but it can hide why submission is unavailable.
If you disable it, make the requirements clear and ensure the form remains usable.
Allowing submission and showing specific errors is often easier for users.
Why should server-side validation repeat browser validation?
Because users can bypass or modify browser-side JavaScript and HTML.
The server must independently decide whether submitted data is acceptable.
What should I learn after JavaScript form validation?
Learn the JavaScript Fetch API next. It lets your code send and receive data without requiring a traditional full-page navigation.
Summary
JavaScript form validation checks whether form values meet your rules before they are accepted or sent.
Start with useful HTML constraints such as:
required
type="email"
minlength
maxlength
min
max
pattern
Then use JavaScript when you need custom behavior.
You learned how to:
- Listen for form submission
- Use
preventDefault() - Check required fields
- Use
trim() - Validate email fields
- Validate password length
- Compare password fields
- Validate checkboxes
- Validate select menus
- Check number ranges
- Use
validity - Use
checkValidity() - Use
reportValidity() - Use
setCustomValidity() - Show custom error messages
- Clear old errors
- Add
aria-invalid - Focus an invalid field
- Read data with
FormData - Keep validation accessible
- Separate client-side validation from server-side security
Good validation helps users correct mistakes quickly.
It should never be your only protection for important application data.
Continue Learning JavaScript
Previous Lesson: JavaScript Events Explained
Course Home: JavaScript Tutorial for Beginners
Next Lesson: JavaScript Fetch API Explained
In the next lesson, you will learn how fetch() sends HTTP requests, reads JSON responses, handles errors, and connects your JavaScript forms and pages to APIs.
