ThFormValidator is a light, extensible, dependency-free plugin for validating forms. It has some basic validations built in and allows you to add your own.
Include the script on your page:
<script src="https://cdn.treehouseinternetgroup.com/cms_core/assets/js/th_form_validator.js"></script>
The plugin can be instantiated using the new
keyword: new ThFormValidator(<form id>, {<options object>})
.
Pass the form’s ID as the first parameter:
<script>
const validator = new ThFormValidator("contact_form");
</script>
Options can be added as an object:
<script>
const validator = new ThFormValidator("contact_form", {disableSubmit: true});
</script>
When using built-in and custom validators, add the validator name to the end of data-validate-
attribute and pass any parameters as the value:
<!-- Validate a UK phone number -->
<input id="Phone" name="phone_number" type="text" data-validate-phone="gb">
<!-- Validate a US phone number (us is set by default - no opt attribute required) -->
<input id="Phone" name="phone_number" type="text" data-validate-phone">
Option | Type | Default | Description |
---|---|---|---|
disableSubmit |
Boolean | false | Prevents adding a submit event listener on init. Allows you to define the submit event yourself. |
validateOnBlur |
Boolean | true | Whether to validate a field when it looses focus. |
errorMessageClass |
String | ‘error’ | The class name added to error message elements. |
errorMessageTag |
String | ‘label’ | The tag used for creating error message elements. |
errorInputClass |
String | ‘error’ | The class name added to the input field for invalid inputs |
customValidators |
Object | see below | Object defining custom validation functions |
Validators use the data-validate-xxxx
attribute to define validation (where xxxx
is the validator function name). If not passing additional parameters (sticking to default options), there is no need to include a value for your validator attribute. Here are the built-in validators:
Validator | Parameters | Values | Example |
---|---|---|---|
notequal | field to compare - required | field selector string (i.e. “#First_Name”) | <input id="Last_Name" type="text" name="Last_Name" data-validate-notequal="#First_Name"> |
zip | country | “us” - ‘merica! (default) “ca” - America’s hat, Canada (not California - sorry Shannon) “gb” - Harry’s land |
<input id="Zip" type="text" name="Zip_Code" data-validate-zip="ca"> |
phone | country | “us” - works for US and Canada (default) “gb” - guess… |
<input id="Phone" type="text" name="Phone" data-validate-phone="gb"> |
Method | Parameters | Description |
---|---|---|
validateField(field) |
field:selected input element | Validates a single input and returns an error message string |
validateAll() |
group:selected group element or selector string (optional) | Validates all inputs on form or within group element if provided. |
showError(field, error) |
field: selected input element error: error string |
The class name added to error message elements. |
removeError(field) |
field: selected input element | Removes any error messages from the specified field. |
addBlurListener() |
N/A | Sets an event listener for validating inputs when they lose focus. |
addSubmitListener() |
N/A | Sets an event listener for validating the form on submit. |
To define your own validator, add a customValidators
entry to your options object. This entry should also be an object that has functions as its named entries. Validator function names should be all lower case. The function should return an error message if the field is invalid or do nothing if it’s valid. See examples for more info.
const validator = new ThFormValidator("contact_form", {
customValidators: {
custom: function(field) {
// run check on field.value
// if valid - 'return;'
// return error if invalid
}
}
});
If that’s too much work, you can use the pattern
attribute to define a custom validation. See next section.
For custom validators and when using the pattern
constraint, add a title
attribute to define your own error message:
<input id="Zip" type="text" name="Zip_Code" data-validate-myvalidator title="Please enter a valid ZIP code" required>
<input id="Zip" type="text" name="Zip_Code" pattern="^\d{5}$" maxlength="5" title="Please enter a valid ZIP code" required>
You can disable the built-in submit event listener by passing the disableSubmit
option when instantiating the validator class.
const validator = new ThFormValidator("contact_form", {disableSubmit: true});
At this point you can define your own submit listener. Use the validateAll()
method to validate the entire form. For validating only a specific group of inputs see the examples section.
document.querySelector("#contact_form").addEventListener("submit", function(e) {
e.preventDefault(); //stop default submit action
const errorFields = validator.validateAll(); //validate form
if(errorFields.length) {
//We have errors
errorFields[0].focus();
errorFields[0].scrollIntoView({behavior: "smooth", block: "center"});
return; //exit without submitting form
}
//do stuff if no errors
//submit form
this.submit();
});
Setting a custom error message class and element
const validator = new ThFormValidator("contact_form", {
errorMessageClass: 'error-msg',
errorMessageTag: 'div'
});
Changing the default class for invalid inputs
const validator = new ThFormValidator("contact_form", {
errorInputClass: 'invalid'
});
Adding a custom, more robust email validator
const validator = new ThFormValidator("contact_form", {
customValidators: {
email: function (field) {
const pattern = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*(\.\w{2,})+$/;
const valid = pattern.test(field.value)
if(valid) return; //do nothing
return "Please provide a valid email address." //return error message if not valid
}
}
}
Apply the validator to the input by setting a data-validate-xxxx
attribute, where xxxx
is the name of your validator function created above. Pass validation parameters as the value (i.e.: data-validate-phone="us"
). If no parameters are required, there is no need to set a value for the attribute:
<input id="Email_Address" type="email" name="Email_Address" maxlength="200" data-validate-email required>
Validating a group of inputs
Pass the group element selector to the validateAll
method of your validator object:
const errorFields = validator.validateAll('.step1');
if (errorFields.length) {
//we have fields with errors
errorFields[0].focus();
errorFields[0].scrollIntoView({behavior: "smooth", block: "center"});
} else {
//do stuff if group is valid
}
Validating a single input
This is not necessary when using the default validateOnBlur
option, but included just in case.
Select the field you want to validate and pass it to the validateField
method of your validator object:
const field = document.querySelector("#First_Name");
const error = validator.validateField(field);
if (error) {
//we have an error
validator.showError(field, error);
field.focus();
field.scrollIntoView({behavior: "smooth", block: "center"});
} else {
validator.removeError(field);
//do stuff if field is valid
}