Skip to content
beginnerPhase 30 · HTML

Form Validation

Use built-in HTML5 validation with patterns, required fields, and custom constraints.

30m
0 problems
Topic Progress0%

Built-in Validation

HTML5 provides built-in validation that works without JavaScript.

Validation Attributes

<!-- Required field -->
<input type="text" required>

<!-- Email format -->
<input type="email" required>
<!-- Validates: user@example.com -->

<!-- URL format -->
<input type="url" required>
<!-- Validates: https://example.com -->

<!-- Number range -->
<input type="number" min="0" max="100" step="1">

<!-- Length constraints -->
<input type="text" minlength="3" maxlength="20">

<!-- Pattern matching -->
<input type="text" pattern="[A-Za-z]{3}">

Validation States

const input = document.querySelector('input');

// Check validity
input.checkValidity();  // true or false

// Get validation message
input.validationMessage;  // "Please fill out this field"

// Validity state object
input.validity.valueMissing;      // required but empty
input.validity.typeMismatch;      // wrong format (email, url)
input.validity.tooShort;          // below minlength
input.validity.tooLong;           // above maxlength
input.validity.rangeUnderflow;    // below min
input.validity.rangeOverflow;     // above max
input.validity.stepMismatch;      // wrong step value
input.validity.patternMismatch;   // doesn't match pattern
input.validity.valid;             // all checks passed

Styling Validation States

/* Valid input */
input:valid {
    border-color: green;
    background-color: #f0fff0;
}

/* Invalid input */
input:invalid {
    border-color: red;
    background-color: #fff0f0;
}

/* Required field */
input:required {
    border-left: 3px solid orange;
}

/* Focus state */
input:focus:invalid {
    box-shadow: 0 0 5px rgba(255, 0, 0, 0.5);
}

Disabling Validation

<!-- Disable for entire form -->
<form novalidate>
    <input type="email" required>
    <button type="submit">Submit</button>
</form>

<!-- Disable for specific button -->
<button type="submit" formnovalidate>Save Draft</button>

Custom Validation Messages

const input = document.querySelector('input');

input.addEventListener('invalid', (e) => {
    e.preventDefault();  // Prevent default browser message
    
    if (input.validity.valueMissing) {
        input.setCustomValidity('Please enter your email');
    } else if (input.validity.typeMismatch) {
        input.setCustomValidity('Please enter a valid email address');
    } else {
        input.setCustomValidity('');  // Clear custom message
    }
});

// Reset on input
input.addEventListener('input', () => {
    input.setCustomValidity('');
});

Pattern Matching

The pattern attribute lets you validate input using regular expressions.

Common Patterns

<!-- Phone number (US) -->
<input type="tel" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">
<!-- Format: 123-456-7890 -->

<!-- Alphanumeric -->
<input type="text" pattern="[A-Za-z0-9]+">

<!-- Letters only -->
<input type="text" pattern="[A-Za-z]+">

<!-- Capital letters -->
<input type="text" pattern="[A-Z]+">

<!-- At least 3 characters -->
<input type="text" pattern=".{3,}">

<!-- Credit card (basic) -->
<input type="text" pattern="[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}">
<!-- Format: 1234-5678-9012-3456 -->

<!-- Social Security Number -->
<input type="text" pattern="[0-9]{3}-[0-9]{2}-[0-9]{4}">
<!-- Format: 123-45-6789 -->

<!-- ZIP code (US) -->
<input type="text" pattern="[0-9]{5}(-[0-9]{4})?">
<!-- Format: 12345 or 12345-6789 -->

Pattern Syntax

.       → Any character (except newline)
\\d      → Digit [0-9]
\\w      → Word character [A-Za-z0-9_]
\\s      → Whitespace
[A-Z]   → Uppercase letter
[a-z]   → Lowercase letter
[0-9]   → Digit
[^abc]  → Not a, b, or c

*       → 0 or more
+       → 1 or more
?       → 0 or 1
{n}     → Exactly n
{n,}    → n or more
{n,m}   → Between n and m

^       → Start of string
$       → End of string
(abc)   → Group
a|b     → a or b

Real-World Examples

<!-- Username (3-20 chars, alphanumeric) -->
<input type="text" pattern="^[a-zA-Z0-9]{3,20}$">

<!-- Password (min 8 chars, 1 uppercase, 1 number) -->
<input type="password" pattern="^(?=.*[A-Z])(?=.*[0-9]).{8,}$">

<!-- Date (MM/DD/YYYY) -->
<input type="text" pattern="^(0[1-9]|1[0-2])/(0[1-9]|[12][0-9]|3[01])/[0-9]{4}$">

<!-- Hex color -->
<input type="text" pattern="^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$">

<!-- ISBN-13 -->
<input type="text" pattern="^97[89]-[0-9]-[0-9]{4}-[0-9]{4}-[0-9]$">

Pattern Validation with JavaScript

const input = document.querySelector('input[pattern]');
const pattern = new RegExp(input.pattern);

input.addEventListener('input', () => {
    if (input.value && !pattern.test(input.value)) {
        input.setCustomValidity('Invalid format');
    } else {
        input.setCustomValidity('');
    }
});

Custom Validation

For complex validation rules, use JavaScript with the Constraint Validation API.

Constraint Validation API

const form = document.querySelector('form');
const email = document.querySelector('input[type="email"]');

// Check validity
email.checkValidity();  // true or false

// Get message
email.validationMessage;  // "Please fill out this field"

// Validity object
email.validity = {
    valueMissing: false,
    typeMismatch: false,
    tooShort: false,
    tooLong: false,
    rangeUnderflow: false,
    rangeOverflow: false,
    stepMismatch: false,
    patternMismatch: false,
    customError: false,
    valid: true
};

// Set custom error
email.setCustomValidity('Email already exists');

// Reset custom error
email.setCustomValidity('');

Form Submit Handler

form.addEventListener('submit', (e) => {
    // Prevent default validation
    e.preventDefault();
    
    // Custom validation
    let isValid = true;
    
    // Validate each field
    document.querySelectorAll('input[required]').forEach(input => {
        if (!input.value.trim()) {
            showError(input, 'This field is required');
            isValid = false;
        } else {
            clearError(input);
        }
    });
    
    // Validate email format
    const email = document.querySelector('input[type="email"]');
    if (email.value && !isValidEmail(email.value)) {
        showError(email, 'Please enter a valid email');
        isValid = false;
    }
    
    // Validate password strength
    const password = document.querySelector('input[type="password"]');
    if (password.value && !isStrongPassword(password.value)) {
        showError(password, 'Password must be at least 8 characters with uppercase and number');
        isValid = false;
    }
    
    if (isValid) {
        form.submit();
    }
});

// Helper functions
function isValidEmail(email) {
    return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);
}

function isStrongPassword(password) {
    return /^(?=.*[A-Z])(?=.*[0-9]).{8,}$/.test(password);
}

function showError(input, message) {
    const error = input.nextElementSibling;
    if (error && error.classList.contains('error')) {
        error.textContent = message;
    } else {
        const div = document.createElement('div');
        div.className = 'error';
        div.textContent = message;
        input.parentNode.insertBefore(div, input.nextSibling);
    }
    input.classList.add('invalid');
}

function clearError(input) {
    const error = input.nextElementSibling;
    if (error && error.classList.contains('error')) {
        error.remove();
    }
    input.classList.remove('invalid');
}

Real-Time Validation

// Validate on input (real-time feedback)
document.querySelectorAll('input').forEach(input => {
    input.addEventListener('input', () => {
        if (input.checkValidity()) {
            input.classList.remove('invalid');
            input.classList.add('valid');
        } else {
            input.classList.remove('valid');
            input.classList.add('invalid');
        }
    });
});

Server-Side Validation

// Always validate on server too!
app.post('/api/users', (req, res) => {
    const { email, password } = req.body;
    
    // Server-side validation
    if (!email || !isValidEmail(email)) {
        return res.status(400).json({ error: 'Invalid email' });
    }
    
    if (!password || password.length < 8) {
        return res.status(400).json({ error: 'Password too short' });
    }
    
    // Process valid data
    createUser({ email, password });
    res.json({ success: true });
});

Practice Problems

0/3solved
Build Form Validation Component

Create a reusable React component implementing Form Validation. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Form Validation Testing

Write unit and integration tests for Form Validation using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Form Validation Performance

Optimize Form Validation for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What does the required attribute do?

Question 1 options

2. What is the pattern attribute used for?

Question 2 options

3. Why should you always validate on the server?

Question 3 options

4. What does setCustomValidity() do?

Question 4 options

Flashcards

Question

What is HTML5 form validation?

Answer

Built-in validation using attributes like required, pattern, min/max, minlength/maxlength. Works without JavaScript.

Question

What is the Constraint Validation API?

Answer

JavaScript API for custom validation: checkValidity(), setCustomValidity(), validity object, validationMessage.

Question

Why is client-side validation not enough?

Answer

It can be bypassed by disabling JavaScript or using tools. Always validate on the server too.

Question

What is Form Validation?

Answer

Form Validation is a key concept in frontend development.

Question

When to use Form Validation?

Answer

Use Form Validation when building production systems that require reliability, scalability, and maintainability.

Revision Notes

Key Takeaways

  • 1.HTML5 provides built-in validation with no JavaScript needed
  • 2.Use pattern attribute for regex-based validation
  • 3.Always validate on the server - client-side can be bypassed
  • 4.Provide clear, helpful error messages
  • 5.Use the Constraint Validation API for complex rules

Interview Tips

  • Know the difference between client-side and server-side validation
  • Understand the Constraint Validation API
  • Be able to write validation patterns for common formats
  • Know why server-side validation is essential

Cheat Sheet

Form Validation Cheat Sheet

Built-in Attributes:

  • required: Must be filled
  • type="email"/"url": Format validation
  • min/max: Number range
  • minlength/maxlength: Text length
  • pattern: Regex validation

Constraint Validation API:

  • checkValidity(): Returns boolean
  • validationMessage: Error message
  • setCustomValidity(): Set custom error
  • validity: Object with error states

Styling:

  • :valid - Valid input
  • :invalid - Invalid input
  • :required - Required field

Best Practices:

  • Always validate on server too
  • Provide clear error messages
  • Validate in real-time
  • Handle edge cases