Academic Block

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

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

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!');

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

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();

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'
});

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

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');

Common Validation Patterns

Validation Type Pattern/Method Example
Email /^[^\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'));
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.

📝 JavaScript Code
👁 Console Output

Click "Run Code" to see the output here.

Ctrl + Enter to run code Esc to close