Basic Form Validation
A basic example demonstrating form validation with common field types including text, email, and required fields.
This example shows how to implement client-side validation with FormValidation library.
Basic Form Validation
Form submitted successfully!
/**
* Demonstrates FormValidation library with common field types
*/
class KTExampleFormValidationBasic {
static init() {
const form = document.getElementById('kt_form_validation_basic');
if (!form) return;
// Initialize FormValidation without Framework plugin
const fv = FormValidation.formValidation(form, {
fields: {
name: {
validators: {
notEmpty: {
message: 'Name is required'
},
stringLength: {
min: 2,
max: 50,
message: 'Name must be between 2 and 50 characters'
}
}
},
email: {
validators: {
notEmpty: {
message: 'Email is required'
},
emailAddress: {
message: 'Please enter a valid email address'
}
}
},
phone: {
validators: {
notEmpty: {
message: 'Phone number is required'
},
phone: {
country: 'US',
message: 'Please enter a valid phone number'
}
}
},
website: {
validators: {
uri: {
message: 'Please enter a valid URL'
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
})
}
});
// Handle validation events for custom Tailwind CSS styling
fv.on('core.field.valid', function(e) {
const element = e.element;
// Remove error styling
element.classList.remove('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Add success styling
element.classList.add('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Remove any existing error message
const errorElement = element.parentNode.querySelector('.fv-error-message');
if (errorElement) {
errorElement.remove();
}
});
fv.on('core.field.invalid', function(e) {
const element = e.element;
const message = e.result.message;
// Remove success styling
element.classList.remove('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Add error styling
element.classList.add('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Remove any existing error message
const existingError = element.parentNode.querySelector('.fv-error-message');
if (existingError) {
existingError.remove();
}
// Add error message with Tailwind CSS classes
const errorElement = document.createElement('div');
errorElement.className = 'fv-error-message text-red-600 text-sm mt-1 flex items-center';
errorElement.innerHTML = `
<svg class="w-4 h-4 mr-1 flex-shrink-0" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" fill-rule="evenodd">
</path>
</svg>
${message}
`;
element.parentNode.appendChild(errorElement);
});
// Handle form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
fv.validate().then(function(status) {
if (status === 'Valid') {
// Show success message
const successAlert = document.getElementById('success-alert');
if (successAlert) {
successAlert.classList.remove('hidden');
setTimeout(() => {
successAlert.classList.add('hidden');
}, 3000);
}
// Reset form
form.reset();
fv.resetForm(true);
// Clear all error messages
const errorMessages = form.querySelectorAll('.fv-error-message');
errorMessages.forEach(msg => msg.remove());
// Reset input styling to default Tailwind classes
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.classList.remove('border-red-500', 'border-green-500', 'focus:border-red-500', 'focus:border-green-500', 'focus:ring-red-500', 'focus:ring-green-500');
input.classList.add('border-gray-300', 'focus:border-blue-500', 'focus:ring-blue-500');
});
}
});
});
}
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
KTExampleFormValidationBasic.init();
});
<!-- Basic Form Validation Example -->
<div class="card">
<div class="card-header">
<h3 class="card-title">
Basic Form Validation
</h3>
<div class="card-toolbar">
<span class="badge badge-light-primary">
FormValidation
</span>
</div>
</div>
<div class="card-body">
<form class="space-y-6" id="kt_form_validation_basic">
<!-- Name Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="name">
Full Name
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="name" name="name" placeholder="Enter your full name" type="text"/>
</div>
<!-- Email Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="email">
Email Address
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="email" name="email" placeholder="Enter your email address" type="email"/>
</div>
<!-- Phone Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="phone">
Phone Number
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="phone" name="phone" placeholder="Enter your phone number" type="tel"/>
</div>
<!-- Website Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="website">
Website (Optional)
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="website" name="website" placeholder="https://example.com" type="url"/>
</div>
<!-- Submit Button -->
<div class="form-group">
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition duration-200" type="submit">
Submit Form
</button>
</div>
</form>
<!-- Success Alert -->
<div class="hidden bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded mt-4" id="success-alert">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" fill-rule="evenodd">
</path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium">
Form submitted successfully!
</p>
</div>
</div>
</div>
</div>
</div>
Email Validation
An advanced email validation example demonstrating various email validation scenarios including
domain validation, disposable email detection, and custom validation rules.
Email Validation
Email validation successful!
/**
* Demonstrates advanced email validation with FormValidation library
*/
class KTExampleFormValidationEmail {
static init() {
const form = document.getElementById('kt_form_validation_email');
if (!form) return;
// Initialize FormValidation without Framework plugin
const fv = FormValidation.formValidation(form, {
fields: {
email: {
validators: {
notEmpty: {
message: 'Email is required'
},
emailAddress: {
message: 'Please enter a valid email address'
},
callback: {
message: 'Please enter a valid email address',
callback: function(input) {
const email = input.value;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
}
},
confirmEmail: {
validators: {
notEmpty: {
message: 'Please confirm your email'
},
emailAddress: {
message: 'Please enter a valid email address'
},
identical: {
compare: function() {
return form.querySelector('[name="email"]').value;
},
message: 'Email addresses do not match'
}
}
},
additionalEmail: {
validators: {
emailAddress: {
message: 'Please enter a valid email address'
},
callback: {
message: 'Please enter a valid email address',
callback: function(input) {
const email = input.value;
if (!email) return true; // Allow empty
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
})
}
});
// Handle validation events for custom Tailwind CSS styling
fv.on('core.field.valid', function(e) {
const element = e.element;
// Remove error styling
element.classList.remove('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Add success styling
element.classList.add('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Remove any existing error message
const errorElement = element.parentNode.querySelector('.fv-error-message');
if (errorElement) {
errorElement.remove();
}
});
fv.on('core.field.invalid', function(e) {
const element = e.element;
const message = e.result.message;
// Remove success styling
element.classList.remove('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Add error styling
element.classList.add('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Remove any existing error message
const existingError = element.parentNode.querySelector('.fv-error-message');
if (existingError) {
existingError.remove();
}
// Add error message with Tailwind CSS classes
const errorElement = document.createElement('div');
errorElement.className = 'fv-error-message text-red-600 text-sm mt-1 flex items-center';
errorElement.innerHTML = `
<svg class="w-4 h-4 mr-1 flex-shrink-0" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" fill-rule="evenodd">
</path>
</svg>
${message}
`;
element.parentNode.appendChild(errorElement);
});
// Handle form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
fv.validate().then(function(status) {
if (status === 'Valid') {
// Show success message
const successAlert = document.getElementById('success-alert');
if (successAlert) {
successAlert.classList.remove('hidden');
setTimeout(() => {
successAlert.classList.add('hidden');
}, 3000);
}
// Reset form
form.reset();
fv.resetForm(true);
// Clear all error messages
const errorMessages = form.querySelectorAll('.fv-error-message');
errorMessages.forEach(msg => msg.remove());
// Reset input styling to default Tailwind classes
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.classList.remove('border-red-500', 'border-green-500', 'focus:border-red-500', 'focus:border-green-500', 'focus:ring-red-500', 'focus:ring-green-500');
input.classList.add('border-gray-300', 'focus:border-blue-500', 'focus:ring-blue-500');
});
}
});
});
}
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
KTExampleFormValidationEmail.init();
});
<!-- Email Validation Example -->
<div class="card">
<div class="card-header">
<h3 class="card-title">
Email Validation
</h3>
<div class="card-toolbar">
<span class="badge badge-light-primary">
FormValidation
</span>
</div>
</div>
<div class="card-body">
<form class="space-y-6" id="kt_form_validation_email">
<!-- Primary Email Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="email">
Primary Email
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="email" name="email" placeholder="Enter your primary email" type="email"/>
<small class="text-gray-500 text-sm">
This will be your main contact email
</small>
</div>
<!-- Confirm Email Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="confirmEmail">
Confirm Email
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="confirmEmail" name="confirmEmail" placeholder="Confirm your email address" type="email"/>
</div>
<!-- Additional Email Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="additionalEmail">
Additional Email (Optional)
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="additionalEmail" name="additionalEmail" placeholder="Enter additional email address" type="email"/>
<small class="text-gray-500 text-sm">
For backup or business purposes
</small>
</div>
<!-- Submit Button -->
<div class="form-group">
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition duration-200" type="submit">
Validate Emails
</button>
</div>
</form>
<!-- Success Alert -->
<div class="hidden bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded mt-4" id="success-alert">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" fill-rule="evenodd">
</path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium">
Email validation successful!
</p>
</div>
</div>
</div>
</div>
</div>
Password Strength Validation
A comprehensive password strength validation example that checks password complexity,
confirmation matching, and provides real-time strength feedback with visual indicators.
Password Strength Validation
Account created successfully!
/**
* Demonstrates password strength validation with FormValidation library
*/
class KTExampleFormValidationPasswordStrength {
static init() {
const form = document.getElementById('kt_form_validation_password');
if (!form) return;
// Password strength checker
function checkPasswordStrength(password) {
const requirements = {
length: password.length >= 8,
uppercase: /[A-Z]/.test(password),
lowercase: /[a-z]/.test(password),
number: /\d/.test(password),
special: /[!@#$%^&*(),.?":{}|<>]/.test(password)
};
// Calculate strength score (0-100)
let score = 0;
if (requirements.length) score += 20;
if (requirements.uppercase) score += 20;
if (requirements.lowercase) score += 20;
if (requirements.number) score += 20;
if (requirements.special) score += 20;
return { requirements, score };
}
// Update requirement indicators
function updateRequirementIndicator(elementId, isMet) {
const element = document.getElementById(elementId);
if (element) {
if (isMet) {
element.classList.remove('text-red-500');
element.classList.add('text-green-500');
element.innerHTML = element.innerHTML.replace('✗', '✓');
} else {
element.classList.remove('text-green-500');
element.classList.add('text-red-500');
element.innerHTML = element.innerHTML.replace('✓', '✗');
}
}
}
// Update strength meter
function updateStrengthMeter(score) {
const meter = document.getElementById('password-strength-meter');
const strengthText = document.getElementById('password-strength-text');
if (meter && strengthText) {
meter.value = score;
if (score < 40) {
strengthText.textContent = 'Weak';
strengthText.className = 'text-red-600 font-medium';
} else if (score < 80) {
strengthText.textContent = 'Medium';
strengthText.className = 'text-yellow-600 font-medium';
} else {
strengthText.textContent = 'Strong';
strengthText.className = 'text-green-600 font-medium';
}
}
}
// Password input event listener
const passwordInput = form.querySelector('[name="password"]');
if (passwordInput) {
passwordInput.addEventListener('input', function() {
const password = this.value;
const { requirements, score } = checkPasswordStrength(password);
updateRequirementIndicator('req-length', requirements.length);
updateRequirementIndicator('req-uppercase', requirements.uppercase);
updateRequirementIndicator('req-lowercase', requirements.lowercase);
updateRequirementIndicator('req-number', requirements.number);
updateRequirementIndicator('req-special', requirements.special);
updateStrengthMeter(score);
});
}
// Initialize FormValidation without Framework plugin
const fv = FormValidation.formValidation(form, {
fields: {
password: {
validators: {
notEmpty: {
message: 'Password is required'
},
stringLength: {
min: 8,
message: 'Password must be at least 8 characters long'
},
callback: {
message: 'Password must meet all requirements',
callback: function(input) {
const password = input.value;
const { requirements } = checkPasswordStrength(password);
return requirements.length && requirements.uppercase &&
requirements.lowercase && requirements.number && requirements.special;
}
}
}
},
confirmPassword: {
validators: {
notEmpty: {
message: 'Please confirm your password'
},
identical: {
compare: function() {
return form.querySelector('[name="password"]').value;
},
message: 'Passwords do not match'
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
})
}
});
// Handle validation events for custom Tailwind CSS styling
fv.on('core.field.valid', function(e) {
const element = e.element;
// Remove error styling
element.classList.remove('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Add success styling
element.classList.add('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Remove any existing error message
const errorElement = element.parentNode.querySelector('.fv-error-message');
if (errorElement) {
errorElement.remove();
}
});
fv.on('core.field.invalid', function(e) {
const element = e.element;
const message = e.result.message;
// Remove success styling
element.classList.remove('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Add error styling
element.classList.add('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Remove any existing error message
const existingError = element.parentNode.querySelector('.fv-error-message');
if (existingError) {
existingError.remove();
}
// Add error message with Tailwind CSS classes
const errorElement = document.createElement('div');
errorElement.className = 'fv-error-message text-red-600 text-sm mt-1 flex items-center';
errorElement.innerHTML = `
<svg class="w-4 h-4 mr-1 flex-shrink-0" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" fill-rule="evenodd">
</path>
</svg>
${message}
`;
element.parentNode.appendChild(errorElement);
});
// Handle form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
fv.validate().then(function(status) {
if (status === 'Valid') {
// Show success message
const successAlert = document.getElementById('success-alert');
if (successAlert) {
successAlert.classList.remove('hidden');
setTimeout(() => {
successAlert.classList.add('hidden');
}, 3000);
}
// Reset form
form.reset();
fv.resetForm(true);
// Clear all error messages
const errorMessages = form.querySelectorAll('.fv-error-message');
errorMessages.forEach(msg => msg.remove());
// Reset input styling to default Tailwind classes
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.classList.remove('border-red-500', 'border-green-500', 'focus:border-red-500', 'focus:border-green-500', 'focus:ring-red-500', 'focus:ring-green-500');
input.classList.add('border-gray-300', 'focus:border-blue-500', 'focus:ring-blue-500');
});
// Reset strength meter
updateStrengthMeter(0);
updateRequirementIndicator('req-length', false);
updateRequirementIndicator('req-uppercase', false);
updateRequirementIndicator('req-lowercase', false);
updateRequirementIndicator('req-number', false);
updateRequirementIndicator('req-special', false);
}
});
});
}
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
KTExampleFormValidationPasswordStrength.init();
});
<!-- Password Strength Validation Example -->
<div class="card">
<div class="card-header">
<h3 class="card-title">
Password Strength Validation
</h3>
<div class="card-toolbar">
<span class="badge badge-light-primary">
FormValidation
</span>
</div>
</div>
<div class="card-body">
<form class="space-y-6" id="kt_form_validation_password">
<!-- Password Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="password">
Password
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="password" name="password" placeholder="Enter your password" type="password"/>
<!-- Password Strength Meter -->
<div class="mt-3">
<div class="flex items-center justify-between mb-2">
<span class="text-sm font-medium text-gray-700">
Password Strength:
</span>
<span class="text-sm font-medium text-gray-500" id="password-strength-text">
Weak
</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-red-500 h-2 rounded-full transition-all duration-300" id="password-strength-meter" style="width: 0%">
</div>
</div>
</div>
<!-- Password Requirements -->
<div class="mt-3 space-y-1">
<p class="text-sm font-medium text-gray-700 mb-2">
Requirements:
</p>
<div class="text-sm text-red-500" id="req-length">
✗ At least 8 characters
</div>
<div class="text-sm text-red-500" id="req-uppercase">
✗ One uppercase letter
</div>
<div class="text-sm text-red-500" id="req-lowercase">
✗ One lowercase letter
</div>
<div class="text-sm text-red-500" id="req-number">
✗ One number
</div>
<div class="text-sm text-red-500" id="req-special">
✗ One special character
</div>
</div>
</div>
<!-- Confirm Password Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="confirmPassword">
Confirm Password
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="confirmPassword" name="confirmPassword" placeholder="Confirm your password" type="password"/>
</div>
<!-- Submit Button -->
<div class="form-group">
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition duration-200" type="submit">
Create Account
</button>
</div>
</form>
<!-- Success Alert -->
<div class="hidden bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded mt-4" id="success-alert">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" fill-rule="evenodd">
</path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium">
Account created successfully!
</p>
</div>
</div>
</div>
</div>
</div>
Credit Card Validation
A comprehensive credit card validation example that validates card numbers,
expiry dates, CVV codes, and automatically detects card types with visual feedback.
Credit Card Validation
Payment processed successfully!
/**
* Demonstrates credit card validation with FormValidation library
*/
class KTExampleFormValidationCreditCard {
static init() {
const form = document.getElementById('kt_form_validation_credit_card');
if (!form) return;
// Credit card validation functions
function luhnCheck(cardNumber) {
const digits = cardNumber.replace(/\D/g, '');
let sum = 0;
let isEven = false;
// Loop through values starting from the rightmost side
for (let i = digits.length - 1; i >= 0; i--) {
let digit = parseInt(digits[i]);
if (isEven) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
isEven = !isEven;
}
return (sum % 10) === 0;
}
// Detect card type
function detectCardType(cardNumber) {
const patterns = {
visa: /^4/,
mastercard: /^5[1-5]/,
amex: /^3[47]/,
discover: /^6(?:011|5)/,
diners: /^3(?:0[0-5]|[68])/,
jcb: /^(?:2131|1800|35\d{3})/
};
for (const [type, pattern] of Object.entries(patterns)) {
if (pattern.test(cardNumber)) {
return type;
}
}
return 'unknown';
}
// Update card type display
function updateCardTypeDisplay(cardNumber) {
const cardTypeElement = document.getElementById('card-type');
if (cardTypeElement) {
const cardType = detectCardType(cardNumber);
const cardTypeNames = {
visa: 'Visa',
mastercard: 'Mastercard',
amex: 'American Express',
discover: 'Discover',
diners: 'Diners Club',
jcb: 'JCB',
unknown: ''
};
cardTypeElement.textContent = cardTypeNames[cardType] || '';
}
}
// Format card number with spaces
function formatCardNumber(input) {
let value = input.value.replace(/\D/g, '');
const cardType = detectCardType(value);
// Format based on card type
if (cardType === 'amex') {
value = value.replace(/(\d{4})(\d{6})(\d{5})/, '$1 $2 $3');
} else {
value = value.replace(/(\d{4})(?=\d)/g, '$1 ');
}
input.value = value;
updateCardTypeDisplay(value);
}
// Format expiry date
function formatExpiryDate(input) {
let value = input.value.replace(/\D/g, '');
if (value.length >= 2) {
value = value.substring(0, 2) + '/' + value.substring(2, 4);
}
input.value = value;
}
// Initialize FormValidation without Framework plugin
const fv = FormValidation.formValidation(form, {
fields: {
cardNumber: {
validators: {
notEmpty: {
message: 'Card number is required'
},
callback: {
message: 'Please enter a valid card number',
callback: function(input) {
const cardNumber = input.value.replace(/\s/g, '');
return luhnCheck(cardNumber) && cardNumber.length >= 13 && cardNumber.length <= 19;
}
}
}
},
'expiry-date': {
validators: {
notEmpty: {
message: 'Expiry date is required'
},
callback: {
message: 'Please enter a valid expiry date (MM/YY)',
callback: function(input) {
const value = input.value;
if (!/^\d{2}/\d{2}$/.test(value)) return false;
const [month, year] = value.split('/').map(Number);
const currentDate = new Date();
const currentYear = currentDate.getFullYear() % 100;
const currentMonth = currentDate.getMonth() + 1;
return month >= 1 && month <= 12 &&
(year > currentYear || (year === currentYear && month >= currentMonth));
}
}
}
},
cvv: {
validators: {
notEmpty: {
message: 'CVV is required'
},
digits: {
message: 'CVV must contain only digits'
},
stringLength: {
min: 3,
max: 4,
message: 'CVV must be 3 or 4 digits'
}
}
},
cardholderName: {
validators: {
notEmpty: {
message: 'Cardholder name is required'
},
stringLength: {
min: 2,
max: 50,
message: 'Name must be between 2 and 50 characters'
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
})
}
});
// Handle validation events for custom Tailwind CSS styling
fv.on('core.field.valid', function(e) {
const element = e.element;
// Remove error styling
element.classList.remove('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Add success styling
element.classList.add('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Remove any existing error message
const errorElement = element.parentNode.querySelector('.fv-error-message');
if (errorElement) {
errorElement.remove();
}
});
fv.on('core.field.invalid', function(e) {
const element = e.element;
const message = e.result.message;
// Remove success styling
element.classList.remove('border-green-500', 'focus:border-green-500', 'focus:ring-green-500');
// Add error styling
element.classList.add('border-red-500', 'focus:border-red-500', 'focus:ring-red-500');
// Remove any existing error message
const existingError = element.parentNode.querySelector('.fv-error-message');
if (existingError) {
existingError.remove();
}
// Add error message with Tailwind CSS classes
const errorElement = document.createElement('div');
errorElement.className = 'fv-error-message text-red-600 text-sm mt-1 flex items-center';
errorElement.innerHTML = `
<svg class="w-4 h-4 mr-1 flex-shrink-0" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" fill-rule="evenodd">
</path>
</svg>
${message}
`;
element.parentNode.appendChild(errorElement);
});
// Add input formatting
const cardNumberInput = document.getElementById('cardNumber');
const expiryDateInput = document.getElementById('expiry-date');
if (cardNumberInput) {
cardNumberInput.addEventListener('input', function() {
formatCardNumber(this);
});
}
if (expiryDateInput) {
expiryDateInput.addEventListener('input', function() {
formatExpiryDate(this);
});
}
// Handle form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
fv.validate().then(function(status) {
if (status === 'Valid') {
// Show success message
const successAlert = document.getElementById('success-alert');
if (successAlert) {
successAlert.classList.remove('hidden');
setTimeout(() => {
successAlert.classList.add('hidden');
}, 3000);
}
// Reset form
form.reset();
fv.resetForm(true);
// Clear all error messages
const errorMessages = form.querySelectorAll('.fv-error-message');
errorMessages.forEach(msg => msg.remove());
// Reset input styling to default Tailwind classes
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.classList.remove('border-red-500', 'border-green-500', 'focus:border-red-500', 'focus:border-green-500', 'focus:ring-red-500', 'focus:ring-green-500');
input.classList.add('border-gray-300', 'focus:border-blue-500', 'focus:ring-blue-500');
});
// Reset card type display
updateCardTypeDisplay('');
}
});
});
}
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
KTExampleFormValidationCreditCard.init();
});
<!-- Credit Card Validation Example -->
<div class="card">
<div class="card-header">
<h3 class="card-title">
Credit Card Validation
</h3>
<div class="card-toolbar">
<span class="badge badge-light-primary">
FormValidation
</span>
</div>
</div>
<div class="card-body">
<form class="space-y-6" id="kt_form_validation_credit_card">
<!-- Card Number Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="cardNumber">
Card Number
</label>
<div class="relative">
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 pr-12" id="cardNumber" maxlength="19" name="cardNumber" placeholder="1234 5678 9012 3456" type="text"/>
<div class="absolute inset-y-0 right-0 flex items-center pr-3">
<span class="text-sm text-gray-500" id="card-type">
</span>
</div>
</div>
</div>
<!-- Expiry Date Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="expiry-date">
Expiry Date
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="expiry-date" maxlength="5" name="expiry-date" placeholder="MM/YY" type="text"/>
</div>
<!-- CVV Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="cvv">
CVV
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="cvv" maxlength="4" name="cvv" placeholder="123" type="text"/>
<small class="text-gray-500 text-sm">
3 or 4 digit security code
</small>
</div>
<!-- Cardholder Name Field -->
<div class="form-group">
<label class="block text-sm font-medium text-gray-700 mb-1" for="cardholderName">
Cardholder Name
</label>
<input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" id="cardholderName" name="cardholderName" placeholder="John Doe" type="text"/>
</div>
<!-- Submit Button -->
<div class="form-group">
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition duration-200" type="submit">
Process Payment
</button>
</div>
</form>
<!-- Success Alert -->
<div class="hidden bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded mt-4" id="success-alert">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" fill="currentColor" viewbox="0 0 20 20">
<path clip-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" fill-rule="evenodd">
</path>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium">
Payment processed successfully!
</p>
</div>
</div>
</div>
</div>
</div>