Forms & Validation Get Certified
Form validation ensures that users provide correct and complete data before it is submitted. Client-side validation with JavaScript gives instant feedback and improves the user experience, while server-side validation remains essential for security.
In this lesson you will learn how to validate required fields, email addresses, passwords, phone numbers, credit cards, ZIP codes, and more using regular expressions and custom validation functions.
Required Field Validation
What this code does: Checks whether a field has a non-empty value after trimming whitespace.
const isRequired = function(value) {
return value.trim() !== '';
};
console.log(isRequired('hello')); // true
console.log(isRequired(' ')); // false
console.log(isRequired('')); // false
const isRequired = function(value) { creates a simple function that decides whether a field has real content.return value.trim() !== ''; removes leading/trailing spaces, then checks that something remains. Empty or whitespace-only strings return false.};console.log(isRequired('hello')); prints true.console.log(isRequired(' ')); prints false because after trimming nothing is left.console.log(isRequired('')); prints false.Email Validation
What this code does: Uses a simple but effective regular expression to check email format.
const isValidEmail = function(email) {
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return pattern.test(email);
};
console.log(isValidEmail('user@example.com')); // true
console.log(isValidEmail('invalid-email')); // false
console.log(isValidEmail('user@domain')); // false
const isValidEmail = function(email) {const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; requires at least one non-space/non-@ character, an @, another such sequence, a dot, and a final sequence. It is a practical basic check, not a full RFC-compliant parser.return pattern.test(email);};console.log(isValidEmail('user@example.com')); prints true.console.log(isValidEmail('invalid-email')); prints false.console.log(isValidEmail('user@domain')); prints false.Password Strength Validation
What this code does: Checks length, uppercase, lowercase, number, and special character requirements.
const validatePassword = function(password) {
const errors = [];
if (password.length < 8) errors.push('At least 8 characters');
if (!/[A-Z]/.test(password)) errors.push('One uppercase letter');
if (!/[a-z]/.test(password)) errors.push('One lowercase letter');
if (!/[0-9]/.test(password)) errors.push('One number');
if (!/[^A-Za-z0-9]/.test(password)) errors.push('One special character');
if (errors.length === 0) {
console.log('Password is strong');
return true;
}
console.log('Password needs:', errors.join(', '));
return false;
};
validatePassword('Weak1');
validatePassword('StrongPass1!');
const validatePassword = function(password) {const errors = [];if (password.length < 8) errors.push('At least 8 characters');if (!/[A-Z]/.test(password)) errors.push('One uppercase letter');if (!/[a-z]/.test(password)) errors.push('One lowercase letter');if (!/[0-9]/.test(password)) errors.push('One number');if (!/[^A-Za-z0-9]/.test(password)) errors.push('One special character');if (errors.length === 0) prints a success message and returns true; otherwise it lists every missing requirement and returns false.};validatePassword('Weak1'); fails several rules and logs the missing ones.validatePassword('StrongPass1!'); satisfies every rule and logs success.Phone Number Validation
What this code does: Accepts common US phone formats by stripping non-digits and checking length.
const isValidPhone = function(phone) {
const digits = phone.replace(/\D/g, '');
return digits.length === 10;
};
console.log(isValidPhone('(123) 456-7890')); // true
console.log(isValidPhone('123-456-7890')); // true
console.log(isValidPhone('12345')); // false
const isValidPhone = function(phone) {const digits = phone.replace(/\D/g, ''); strips parentheses, spaces, dashes, and any other non-digit characters.return digits.length === 10; a common rule for US-style phone numbers.};console.log(isValidPhone('(123) 456-7890')); prints true.console.log(isValidPhone('123-456-7890')); prints true.console.log(isValidPhone('12345')); prints false.Managing Form Errors
What this code does: A simple ErrorManager object that stores, removes, and displays field-level errors.
const ErrorManager = {
errors: {},
addError: function(field, message) {
this.errors[field] = message;
console.log('Error added for', field + ':', message);
},
removeError: function(field) {
delete this.errors[field];
console.log('Error removed for', field);
},
hasErrors: function() {
return Object.keys(this.errors).length > 0;
},
clearAll: function() {
this.errors = {};
console.log('All errors cleared');
},
displayErrors: function() {
console.log('Current errors:');
if (this.hasErrors()) {
for (var field in this.errors) {
console.log('-', field + ':', this.errors[field]);
}
} else {
console.log('No errors');
}
}
};
// Usage example
console.log('Managing form errors:');
console.log('');
ErrorManager.addError('username', 'Username is required');
ErrorManager.addError('email', 'Invalid email format');
ErrorManager.displayErrors();
console.log('');
ErrorManager.removeError('username');
ErrorManager.displayErrors();
console.log('');
console.log('Has errors:', ErrorManager.hasErrors());
ErrorManager.clearAll();
const ErrorManager = { errors: {}, ... } holds field-name → message pairs in a plain object.addError stores a message for a field and logs the addition.removeError deletes the entry for a field and logs the removal.hasErrors returns true when at least one error remains.clearAll empties the entire error object.displayErrors prints every current error, or “No errors” if the object is empty.hasErrors, then clears everything.Complete Form Validation Example
Here's a comprehensive example that validates an entire registration form.
What this code does: A complete validator object that runs several rules and returns overall success plus per-field errors.
// Complete form validator
const FormValidator = {
validateUsername: function(username) {
if (username === '') {
return { valid: false, message: 'Username is required' };
}
if (username.length < 3) {
return { valid: false, message: 'Username must be at least 3 characters' };
}
if (!/^[a-zA-Z0-9_]+$/.test(username)) {
return { valid: false, message: 'Username can only contain letters, numbers, underscore' };
}
return { valid: true, message: 'Username is valid' };
},
validateEmail: function(email) {
if (email === '') {
return { valid: false, message: 'Email is required' };
}
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!pattern.test(email)) {
return { valid: false, message: 'Invalid email format' };
}
return { valid: true, message: 'Email is valid' };
},
validatePassword: function(password) {
if (password === '') {
return { valid: false, message: 'Password is required' };
}
if (password.length < 8) {
return { valid: false, message: 'Password must be at least 8 characters' };
}
if (!/[A-Z]/.test(password)) {
return { valid: false, message: 'Password must contain uppercase letter' };
}
if (!/[0-9]/.test(password)) {
return { valid: false, message: 'Password must contain a number' };
}
return { valid: true, message: 'Password is valid' };
},
validateForm: function(formData) {
console.log('Validating registration form...');
console.log('='.repeat(50));
const results = {
username: this.validateUsername(formData.username),
email: this.validateEmail(formData.email),
password: this.validatePassword(formData.password)
};
let isValid = true;
for (var field in results) {
console.log(field + ':', results[field].message);
if (!results[field].valid) {
isValid = false;
}
}
console.log('='.repeat(50));
if (isValid) {
console.log('✓ Form is valid - ready to submit');
} else {
console.log('✗ Form has errors - cannot submit');
}
return isValid;
}
};
// Test 1: Valid form
console.log('Test 1: Valid form data');
FormValidator.validateForm({
username: 'john_doe',
email: 'john@example.com',
password: 'SecurePass123'
});
console.log('');
console.log('');
// Test 2: Invalid form
console.log('Test 2: Invalid form data');
FormValidator.validateForm({
username: 'ab',
email: 'invalid-email',
password: 'weak'
});
const FormValidator = { ... } groups related validation methods together.valid and message.Validating Credit Card Numbers
Credit card validation uses the Luhn algorithm to check if a card number is valid.
What this code does: Implements the Luhn algorithm to check whether a credit card number has a valid checksum.
// Luhn algorithm for credit card validation
const validateCreditCard = function(cardNumber) {
// Remove spaces and dashes
cardNumber = cardNumber.replace(/[\s-]/g, '');
// Check if it contains only digits
if (!/^\d+$/.test(cardNumber)) {
console.log('Invalid: Card number must contain only digits');
return false;
}
// Check length (13-19 digits)
if (cardNumber.length < 13 || cardNumber.length > 19) {
console.log('Invalid: Card number length must be 13-19 digits');
return false;
}
// Luhn algorithm
let sum = 0;
let isEven = false;
for (let i = cardNumber.length - 1; i >= 0; i--) {
let digit = parseInt(cardNumber.charAt(i), 10);
if (isEven) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
isEven = !isEven;
}
if (sum % 10 === 0) {
console.log('Valid credit card number:', cardNumber);
return true;
} else {
console.log('Invalid: Failed Luhn check');
return false;
}
};
// Test cases
console.log('Testing credit card validation:');
console.log('');
validateCreditCard('4532015112830366'); // Valid Visa
console.log('');
validateCreditCard('1234567890123456'); // Invalid
console.log('');
validateCreditCard('5425233430109903'); // Valid Mastercard
const validateCreditCard = function(cardNumber) {cardNumber = cardNumber.replace(/[\s-]/g, '');if (!/^\d+$/.test(cardNumber)) rejects any non-digit characters.Validating ZIP/Postal Codes
ZIP code validation varies by country format.
What this code does: Validates ZIP/postal codes with patterns that can differ by country.
// ZIP code validation by country
const validateZipCode = function(zipCode, country) {
let pattern;
switch(country) {
case 'US':
pattern = /^\d{5}(-\d{4})?$/;
break;
case 'UK':
pattern = /^[A-Z]{1,2}\d{1,2}[A-Z]?\s?\d[A-Z]{2}$/i;
break;
case 'Canada':
pattern = /^[A-Z]\d[A-Z]\s?\d[A-Z]\d$/i;
break;
default:
console.log('Country not supported');
return false;
}
if (pattern.test(zipCode)) {
console.log('Valid', country, 'ZIP/Postal code:', zipCode);
return true;
} else {
console.log('Invalid', country, 'ZIP/Postal code:', zipCode);
return false;
}
};
// Test cases
console.log('Testing ZIP code validation:');
console.log('');
validateZipCode('12345', 'US');
validateZipCode('12345-6789', 'US');
validateZipCode('SW1A 1AA', 'UK');
validateZipCode('K1A 0B1', 'Canada');
console.log('');
validateZipCode('ABCDE', 'US');
validateZipCode('123', 'UK');
const validateZipCode = function(zipCode, country) {let pattern; then a switch selects the correct regular expression./^\d{5}(-\d{4})?$/ matches 5 digits or 5+4 ZIP+4 format.false.Common Validation Patterns
| Validation Type | Pattern/Method | Example |
|---|---|---|
| /^[^\s@]+@[^\s@]+\.[^\s@]+$/ | user@example.com | |
| Phone (US) | /^\d{10}$/ | 1234567890 |
| URL | /^https?:\/\/.+\..+$/ | https://example.com |
| Date (YYYY-MM-DD) | /^\d{4}-\d{2}-\d{2}$/ | 2024-01-15 |
| ZIP (US) | /^\d{5}(-\d{4})?$/ | 12345 or 12345-6789 |
| Alphanumeric | /^[a-zA-Z0-9]+$/ | abc123 |
| Letters Only | /^[a-zA-Z]+$/ | JohnDoe |
| Numbers Only | /^\d+$/ | 12345 |
| Hexadecimal Color | /^#[0-9A-F]{6}$/i | #FF5733 |
| IPv4 Address | /^(\d{1,3}\.){3}\d{1,3}$/ | 192.168.1.1 |
Best Practices for Form Validation
- Always validate on both client-side and server-side
- Provide clear, helpful error messages
- Validate in real-time for better user experience
- Use appropriate input types (email, tel, number, etc.)
- Sanitize all user input to prevent XSS attacks
- Show validation errors near the relevant field
- Use visual indicators (colors, icons) for validation state
- Don't validate on every keystroke for complex rules
- Make required fields clearly marked
- Disable submit button until form is valid
- Test with various edge cases
Common Mistakes in Form Validation
- Only validating on the client-side (server-side is essential)
- Using overly strict validation that rejects valid input
- Not providing clear error messages
- Validating too aggressively (showing errors before user finishes typing)
- Not trimming whitespace before validation
- Forgetting to validate on form submission
- Not handling special characters properly
- Making regex patterns too complex and hard to maintain
- Not considering internationalization (different formats by country)
- Not testing edge cases (empty strings, null, undefined)
Quick Summary
- Form validation ensures users provide valid data before submission
- Use regular expressions for pattern matching (email, phone, URL)
- Validate required fields, length, format, and ranges
- Provide real-time feedback for better user experience
- Create clear, helpful error messages
- Sanitize input to prevent security vulnerabilities
- Always validate on both client and server side
- Use custom validation functions for complex requirements
- Handle form submission properly with preventDefault()
- Test thoroughly with various input scenarios
Try It Yourself
Practice creating validation functions. Try validating different types of data and handling various edge cases.
What this code does: Practice example: build name and age validators, then test them with good and bad input. Click Test My Code to try your own rules.
// Practice: Create your own validator
const MyValidator = {
validateName: function(name) {
if (name === '') {
return { valid: false, message: 'Name is required' };
}
if (name.length < 2) {
return { valid: false, message: 'Name too short' };
}
if (!/^[a-zA-Z\s]+$/.test(name)) {
return { valid: false, message: 'Name can only contain letters' };
}
return { valid: true, message: 'Name is valid' };
},
validateAge: function(age) {
const ageNum = parseInt(age);
if (isNaN(ageNum)) {
return { valid: false, message: 'Age must be a number' };
}
if (ageNum < 18 || ageNum > 120) {
return { valid: false, message: 'Age must be 18-120' };
}
return { valid: true, message: 'Age is valid' };
}
};
// Test your validators
console.log('Testing name validation:');
console.log(MyValidator.validateName('John Doe'));
console.log(MyValidator.validateName('J'));
console.log(MyValidator.validateName('John123'));
console.log('');
console.log('Testing age validation:');
console.log(MyValidator.validateAge('25'));
console.log(MyValidator.validateAge('15'));
console.log(MyValidator.validateAge('abc'));
const MyValidator = { ... } is a simple starter you can extend.{valid, message} object.Tip: Good form validation improves user experience and prevents bad data from entering your system. Always validate on both the client and server side, and provide clear, helpful feedback to users.
Mastering form validation is essential for building robust web applications. Practice creating different validation rules and handling various input scenarios to become proficient in form handling.
🧪 Test Your JavaScript Code
Edit the code on the left and click "Run Code" to see the console output on the right.
Click "Run Code" to see the output here.
Code Explanation
The complete example stays visible. Use Previous and Next to move through its logical blocks.
Select Next to begin exploring the code.