Form Validation & Attributes
Master HTML5 form validation with built-in attributes and constraints. Learn how to create user-friendly forms with client-side validation before a single line of JavaScript.
Why HTML5 Validation Matters
HTML5 introduced powerful built-in form validation that works without JavaScript. This provides:
âš¡ Instant Feedback
Users get immediate validation messages as they fill out forms
📱 Mobile-Friendly
Specialized input types trigger appropriate mobile keyboards
ðŸ›¡ï¸ Security Layer
Client-side validation as first defense (always validate server-side too!)
♿ Accessibility
Screen readers announce validation errors automatically
The required Attribute
The simplest validation: mark fields as mandatory. Forms cannot be submitted until required fields are filled.
<form>
<label for="username">Username (required):</label>
<input type="text" id="username" name="username" required>
<label for="email">Email (required):</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>Input Type Validation
HTML5 input types provide automatic format validation:
type="email"
Validates: Email format (contains @ and valid structure)
Mobile keyboard: Shows @ and .com keys
<input type="email" name="user_email" required>type="url"
Validates: URL format (must include protocol like http://)
Mobile keyboard: Shows / and .com keys
<input type="url" name="website" placeholder="https://example.com">type="tel"
Validates: None (phone formats vary globally)
Mobile keyboard: Shows numeric keypad
<input type="tel" name="phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" placeholder="123-456-7890">type="number"
Validates: Numeric input only
Mobile keyboard: Shows numeric keypad with +/- buttons
<input type="number" name="age" min="18" max="120" required>type="date"
Validates: Valid date format
UI: Native date picker widget
<input type="date" name="birthday" min="1900-01-01" max="2025-12-31">type="range"
Validates: Value within min/max range
UI: Slider control
<input type="range" name="volume" min="0" max="100" value="50">Length Constraints
Control minimum and maximum input length:
| Attribute | Purpose | Works With |
|---|---|---|
minlength | Minimum characters required | text, search, url, tel, email, password |
maxlength | Maximum characters allowed | text, search, url, tel, email, password |
<!-- Password must be at least 8 characters -->
<label for="password">Password (min 8 chars):</label>
<input type="password" id="password" name="password" minlength="8" required>
<!-- Username max 20 characters -->
<label for="username">Username (max 20 chars):</label>
<input type="text" id="username" name="username" maxlength="20" required>
<!-- Bio limited to 500 characters -->
<label for="bio">Bio (max 500 chars):</label>
<textarea id="bio" name="bio" maxlength="500" rows="4"></textarea>maxlength prevents typing beyond the limit.minlength shows an error on submit if too short.Numeric Constraints
For type="number", type="range", and date inputs:
| Attribute | Purpose | Example |
|---|---|---|
min | Minimum value | <input type="number" min="1"> |
max | Maximum value | <input type="number" max="100"> |
step | Valid increments | <input type="number" step="0.1"> |
<!-- Age between 18 and 120 -->
<label for="age">Age (18-120):</label>
<input type="number" id="age" name="age" min="18" max="120" required>
<!-- Price in increments of $0.50 -->
<label for="price">Price:</label>
<input type="number" id="price" name="price" min="0" step="0.50" value="9.99">
<!-- Rating slider 1-5 -->
<label for="rating">Rating (1-5):</label>
<input type="range" id="rating" name="rating" min="1" max="5" value="3">
<!-- Birth date between 1900 and today -->
<label for="birthdate">Birth Date:</label>
<input type="date" id="birthdate" name="birthdate" min="1900-01-01" max="2025-12-31">Pattern Matching with Regular Expressions
The pattern attribute allows custom validation using regular expressions:
<!-- US Phone Number: XXX-XXX-XXXX -->
<label for="phone">Phone (XXX-XXX-XXXX):</label>
<input type="tel" id="phone" name="phone"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
placeholder="123-456-7890"
title="Format: 123-456-7890">
<!-- Postal Code: 5 digits -->
<label for="zip">ZIP Code (5 digits):</label>
<input type="text" id="zip" name="zip"
pattern="[0-9]{5}"
placeholder="12345"
title="Enter a 5-digit ZIP code">
<!-- Username: 3-16 alphanumeric characters -->
<label for="username">Username (3-16 chars, letters/numbers only):</label>
<input type="text" id="username" name="username"
pattern="[a-zA-Z0-9]{3,16}"
title="3-16 characters, letters and numbers only">
<!-- Hexadecimal Color Code -->
<label for="color">Hex Color Code:</label>
<input type="text" id="color" name="color"
pattern="#[0-9A-Fa-f]{6}"
placeholder="#FF5733"
title="Format: #RRGGBB (e.g., #FF5733)">Common Regex Patterns:
| Pattern | Validates |
|---|---|
[0-9]{5} | Exactly 5 digits |
[A-Za-z]{2,10} | 2-10 letters only |
[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,} | Email address |
https?://.+ | URL starting with http:// or https:// |
[0-9]{3}-[0-9]{2}-[0-9]{4} | SSN format: XXX-XX-XXXX |
title attribute with pattern. The title text appears in the validation error message to guide users.Custom Validation Messages
While HTML5 provides default messages, you can customize them with JavaScript:
<form id="myForm">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>
<script>
const emailInput = document.getElementById('email');
emailInput.addEventListener('invalid', (e) => {
if (emailInput.validity.valueMissing) {
emailInput.setCustomValidity('Hey! Email is required.');
} else if (emailInput.validity.typeMismatch) {
emailInput.setCustomValidity('Please enter a valid email address.');
}
});
// Clear custom message on input
emailInput.addEventListener('input', () => {
emailInput.setCustomValidity('');
});
</script>Additional Form Attributes
placeholder
Hint text that disappears when user starts typing
<input type="text" placeholder="Enter your name"><label> for accessibility.readonly
User can see but not edit the value
<input type="text" value="Cannot edit this" readonly>disabled
Field is grayed out and not submitted with form
<input type="text" value="Disabled field" disabled>autofocus
Automatically focuses this field on page load
<input type="text" name="search" autofocus>autocomplete
Controls browser autofill behavior
<input type="email" name="email" autocomplete="email">
<input type="password" name="password" autocomplete="current-password">
<input type="text" name="search" autocomplete="off">multiple
Allow multiple values (for email, file inputs)
<input type="file" name="photos" multiple>
<input type="email" name="recipients" multiple>Complete Form Validation Example
<form action="/register" method="POST">
<!-- Username: 3-16 alphanumeric characters -->
<label for="username">Username *</label>
<input type="text"
id="username"
name="username"
pattern="[a-zA-Z0-9]{3,16}"
title="3-16 characters, letters and numbers only"
required>
<!-- Email validation -->
<label for="email">Email *</label>
<input type="email"
id="email"
name="email"
required>
<!-- Password: minimum 8 characters -->
<label for="password">Password *</label>
<input type="password"
id="password"
name="password"
minlength="8"
title="Minimum 8 characters"
required>
<!-- Age: 18-120 -->
<label for="age">Age *</label>
<input type="number"
id="age"
name="age"
min="18"
max="120"
title="Must be 18 or older"
required>
<!-- Website (optional) -->
<label for="website">Website</label>
<input type="url"
id="website"
name="website"
placeholder="https://example.com">
<!-- Terms agreement -->
<label>
<input type="checkbox" name="terms" required>
I agree to the Terms and Conditions *
</label>
<button type="submit">Register</button>
</form>Disabling Validation
Sometimes you need to bypass validation (e.g., "Save Draft" button):
<form>
<input type="email" name="email" required>
<!-- This button validates -->
<button type="submit">Publish</button>
<!-- This button bypasses validation -->
<button type="submit" formnovalidate>Save Draft</button>
</form>
<!-- Disable validation for entire form -->
<form novalidate>
<input type="email" name="email" required>
<button type="submit">Submit (no validation)</button>
</form>Best Practices
✅ Do
- Always validate on the server (client-side can be bypassed)
- Use appropriate input types for better UX
- Provide clear error messages with
title - Use labels for every input (accessibility)
- Test forms with keyboard-only navigation
- Indicate required fields visually (*)
⌠Don't
- Rely solely on client-side validation for security
- Use placeholder as a replacement for labels
- Make validation messages cryptic or technical
- Disable paste functionality in password fields
- Use
autofocuson every page - Validate on every keystroke (use blur or submit)