Bootstrap 5 Tutorial
v5.3.0Bootstrap 5 Tutorial
Form Validation in Bootstrap 5
Form Validation: Bootstrap 5 provides built-in validation styles and JavaScript for client-side form validation.
Browser Default Validation
HTML5 Built-in Validation
<!-- HTML5 Validation Examples -->
<form>
<!-- Required Email -->
<div class="mb-3">
<label for="html5Email" class="form-label">Email</label>
<input
type="email"
class="form-control"
id="html5Email"
required
placeholder="name@example.com"
>
</div>
<!-- Number with Min/Max -->
<div class="mb-3">
<label for="html5Number" class="form-label">Age</label>
<input
type="number"
class="form-control"
id="html5Number"
min="18"
max="100"
required
>
</div>
<!-- Pattern Validation -->
<div class="mb-3">
<label for="html5Pattern" class="form-label">ZIP Code</label>
<input
type="text"
class="form-control"
id="html5Pattern"
pattern="^\d{5}(-\d{4})?$"
required
title="Enter valid ZIP code"
>
</div>
</form>Bootstrap Validation Styles
Custom Validation Classes
Looks good!
Please provide a valid value.
Good choice!
Please select a valid option.
You must check this box.
You must agree before submitting.
<!-- Valid Input -->
<div class="mb-3">
<label for="validInput" class="form-label">Valid input</label>
<input
type="text"
class="form-control is-valid"
id="validInput"
value="Correct value"
>
<div class="valid-feedback">
Looks good!
</div>
</div>
<!-- Invalid Input -->
<div class="mb-3">
<label for="invalidInput" class="form-label">Invalid input</label>
<input
type="text"
class="form-control is-invalid"
id="invalidInput"
value="Wrong value"
>
<div class="invalid-feedback">
Please provide a valid value.
</div>
</div>
<!-- Valid Select -->
<div class="mb-3">
<label for="validSelect" class="form-label">Valid select</label>
<select class="form-select is-valid" id="validSelect">
<option selected>Open this select menu</option>
</select>
<div class="valid-feedback">
Good choice!
</div>
</div>
<!-- Invalid Checkbox -->
<div class="form-check">
<input class="form-check-input is-invalid" type="checkbox" id="invalidCheck">
<label class="form-check-label" for="invalidCheck">
Invalid checkbox
</label>
<div class="invalid-feedback">
You must agree before submitting.
</div>
</div>Complete Validation Example
Registration Form with Validation
<!-- Complete Validation Example -->
<form onSubmit={handleSubmit} noValidate>
<!-- First Name with Validation -->
<div class="mb-3">
<label for="firstName" class="form-label">First Name *</label>
<input
type="text"
class={`form-control ${errors.firstName ? 'is-invalid' : ''}`}
id="firstName"
name="firstName"
value={formData.firstName}
onChange={handleChange}
required
>
{errors.firstName && (
<div class="invalid-feedback">{errors.firstName}</div>
)}
</div>
<!-- Email with Validation -->
<div class="mb-3">
<label for="email" class="form-label">Email *</label>
<input
type="email"
class={`form-control ${errors.email ? 'is-invalid' : ''}`}
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
>
{errors.email && (
<div class="invalid-feedback">{errors.email}</div>
)}
</div>
<!-- Checkbox with Validation -->
<div class={`form-check ${errors.agreeTerms ? 'is-invalid' : ''}`}>
<input
type="checkbox"
class={`form-check-input ${errors.agreeTerms ? 'is-invalid' : ''}`}
id="agreeTerms"
name="agreeTerms"
checked={formData.agreeTerms}
onChange={handleChange}
required
>
<label class="form-check-label" for="agreeTerms">
I agree to terms *
</label>
{errors.agreeTerms && (
<div class="invalid-feedback">{errors.agreeTerms}</div>
)}
</div>
</form>Server-side Validation Example
Simulated Server Validation
<!-- Server-side Validation Simulation -->
<form onSubmit={handleSubmit}>
<div class="mb-3">
<label for="serverUsername" class="form-label">Check Username</label>
<input
type="text"
class="form-control"
id="serverUsername"
placeholder="Enter username"
required
>
<div class="invalid-feedback"></div>
</div>
<button type="submit" class="btn btn-primary">Check Availability</button>
</form>
<script>
// Simulated server validation
const takenUsernames = ['admin', 'user', 'test', 'demo'];
function handleSubmit(e) {
e.preventDefault();
const username = e.target.username.value;
if (takenUsernames.includes(username.toLowerCase())) {
e.target.username.classList.add('is-invalid');
e.target.nextElementSibling.textContent = 'Username is already taken';
} else {
e.target.username.classList.remove('is-invalid');
e.target.username.classList.add('is-valid');
alert('Username available!');
}
}
</script>Validation with Tooltips
Tooltip Validation Feedback
<!-- Validation with Tooltips -->
<form class="needs-validation" novalidate>
<div class="position-relative">
<label for="tooltipFirstName" class="form-label">First name</label>
<input
type="text"
class="form-control"
id="tooltipFirstName"
required
>
<div class="invalid-tooltip">
Please provide a valid first name.
</div>
</div>
<div class="position-relative">
<label for="tooltipEmail" class="form-label">Email</label>
<div class="input-group has-validation">
<span class="input-group-text">@</span>
<input
type="email"
class="form-control"
id="tooltipEmail"
required
>
<div class="invalid-tooltip">
Please provide a valid email.
</div>
</div>
</div>
</form>Custom Validation Messages
Customizing Validation Feedback
✅ Perfect! This looks great.
❌ Oops! There's an issue with this field.
Please check your input and try again.
Please check your input and try again.
📧❌
⚠️Please enter a valid email address
<!-- Custom Valid Feedback -->
<div class="mb-3">
<input type="text" class="form-control is-valid">
<div class="valid-feedback" style="color: #198754; font-weight: bold;">
✅ Perfect! This looks great.
</div>
</div>
<!-- Custom Invalid Feedback -->
<div class="mb-3">
<input type="text" class="form-control is-invalid">
<div class="invalid-feedback" style="color: #dc3545; font-size: 0.9rem;">
❌ Oops! There's an issue.
<br>
<small>Please check your input.</small>
</div>
</div>
<!-- Validation with Icons -->
<div class="input-group has-validation">
<span class="input-group-text">📧</span>
<input type="email" class="form-control is-invalid">
<span class="input-group-text">
<span class="text-danger">❌</span>
</span>
<div class="invalid-feedback d-flex align-items-center">
<span class="me-2">⚠️</span>
<span>Please enter a valid email</span>
</div>
</div>Real-time Validation
Live Validation Feedback
<!-- Real-time Password Validation -->
<input
type="password"
class="form-control"
id="livePassword"
oninput="validatePassword(this)"
>
<div id="passwordFeedback"></div>
<script>
function validatePassword(input) {
const value = input.value;
const feedback = document.getElementById('passwordFeedback');
if (value.length === 0) {
input.classList.remove('is-valid', 'is-invalid');
feedback.textContent = '';
} else if (value.length < 6) {
input.classList.remove('is-valid');
input.classList.add('is-invalid');
feedback.textContent = 'Password too short';
feedback.className = 'invalid-feedback';
} else if (!/[A-Z]/.test(value)) {
input.classList.remove('is-valid');
input.classList.add('is-invalid');
feedback.textContent = 'Add uppercase letter';
feedback.className = 'invalid-feedback';
} else {
input.classList.remove('is-invalid');
input.classList.add('is-valid');
feedback.textContent = 'Strong password!';
feedback.className = 'valid-feedback';
}
}
</script>Validation Best Practices
Client-side Validation Guidelines
- Always validate on server: Client-side validation is for UX, not security
- Provide immediate feedback: Validate on blur or as user types
- Use clear messages: Explain what's wrong and how to fix it
- Be specific: Don't just say "invalid" - say why it's invalid
- Use appropriate validation: HTML5 attributes first, then custom JavaScript
- Consider accessibility: Ensure validation messages are accessible to screen readers
- Test thoroughly: Test all validation scenarios and edge cases
Common Validation Mistakes
- ❌ Relying solely on client-side validation for security
- ❌ Not clearing validation states when user corrects errors
- ❌ Using vague or technical error messages
- ❌ Validating too early (on every keystroke)
- ❌ Not validating on form submission
- ❌ Forgetting to validate required fields
- ❌ Not testing with different input types and browsers