Hi,
I’m using Metronic Tailwind version and I’m having issues with FormValidation error messages. The validation itself is working (fields are marked invalid), but the error messages are not being displayed correctly, especially for the Toggle Password
field.
Any guidance or example specific to Tailwind + FormValidation would be really helpful.
Thanks in advance!
Hi
The issue is related to the DOM structure of Toggle Password fields and how FormValidation handles error message placement. Here's the specific solution:
The Toggle Password component in Metronic Tailwind has a specific DOM structure:
<div class="kt-input" data-kt-toggle-password="true">
<input type="password" name="password" />
<div class="kt-btn kt-btn-icon" data-kt-toggle-password-trigger="true">
<!-- toggle icons -->
</div>
</div>
// Initialize FormValidation with custom error handling for Toggle Password
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"
}
}
}
},
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"
})
}
});
// Custom error handling for Toggle Password fields
fv.on("core.field.invalid", function(e) {
const element = e.element;
const message = e.result.message;
// Check if this is a Toggle Password field
const togglePasswordContainer = element.closest("[data-kt-toggle-password="true"]");
if (togglePasswordContainer) {
// Remove existing error message
const existingError = togglePasswordContainer.querySelector(".fv-error-message");
if (existingError) {
existingError.remove();
}
// Add error styling to the container
togglePasswordContainer.classList.remove("border-green-500", "focus:border-green-500", "focus:ring-green-500");
togglePasswordContainer.classList.add("border-red-500", "focus:border-red-500", "focus:ring-red-500");
// Create error message element
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 fill-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" clip-rule="evenodd" />
</svg>
${message}
`;
// Insert error message after the Toggle Password container
togglePasswordContainer.parentNode.insertBefore(errorElement, togglePasswordContainer.nextSibling);
} else {
// Standard error handling for regular fields
element.classList.remove("border-green-500", "focus:border-green-500", "focus:ring-green-500");
element.classList.add("border-red-500", "focus:border-red-500", "focus:ring-red-500");
const existingError = element.parentNode.querySelector(".fv-error-message");
if (existingError) {
existingError.remove();
}
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 fill-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" clip-rule="evenodd" />
</svg>
${message}
`;
element.parentNode.appendChild(errorElement);
}
});
// Handle valid fields
fv.on("core.field.valid", function(e) {
const element = e.element;
const togglePasswordContainer = element.closest("[data-kt-toggle-password="true"]");
if (togglePasswordContainer) {
// Remove error styling from container
togglePasswordContainer.classList.remove("border-red-500", "focus:border-red-500", "focus:ring-red-500");
togglePasswordContainer.classList.add("border-green-500", "focus:border-green-500", "focus:ring-green-500");
// Remove error message
const errorElement = togglePasswordContainer.parentNode.querySelector(".fv-error-message");
if (errorElement) {
errorElement.remove();
}
} else {
// Standard valid field handling
element.classList.remove("border-red-500", "focus:border-red-500", "focus:ring-red-500");
element.classList.add("border-green-500", "focus:border-green-500", "focus:ring-green-500");
const errorElement = element.parentNode.querySelector(".fv-error-message");
if (errorElement) {
errorElement.remove();
}
}
});