Modules
The core carries the rules almost every form needs. Everything else — payment details, file checks, national identifiers, colour formats — lives in a module you opt into, so a page never ships validators it does not use.
Loading a module
By name
Name them in modules and they are fetched from beside the core file.
$.validate({
modules: 'security, date, file'
});If they live somewhere else, say so:
$.formUtils.loadModules('security, date', '/assets/js/form-validator/');By import
In a bundled or ESM project, import the module instead. It registers itself on load, which is statically analysable, tree-shakeable, and works under a Content-Security-Policy that forbids injected scripts.
import jQuery from 'jquery-form-validator';
import 'jquery-form-validator/modules/security';
import 'jquery-form-validator/modules/date';
jQuery.validate();A module already registered by an import is skipped rather than fetched again, so naming it in modules as well costs nothing. That is what lets a shared configuration keep working in both a plain page and a bundled app.
Waiting for them
Module loading is asynchronous. If you need to touch a validator the moment it is available, use the callback rather than guessing at a timeout.
$.validate({
modules: 'security',
onModulesLoaded: function () {
// Every named module has registered by this point.
}
});The plugin splits comma, space and hyphen separated lists with the same helper, so a module called constraint-api would be requested as two files named constraint and api, and fail silently. This is why the Constraint Validation bridge is called native. The same applies to any rule name you add yourself.
What each module adds
| Module | Adds | Reference |
|---|---|---|
security | Passwords, credit cards, CVV, breach screening, server-side checks, reCAPTCHA, spam check | Validators → |
date | time and birthdate | Validators → |
file | File size, MIME type, extension, image dimensions and ratio | Validators → |
location | Countries, federal states, longitude/latitude, plus suggestions | Validators → |
sepa | IBAN, BIC and SEPA membership | Validators → |
color | hex, rgb, rgba, hsl, hsla | Validators → |
native | The Constraint Validation API bridge | Below ↓ |
html5 | Translates HTML5 validation attributes into plugin rules | Below ↓ |
logic | Conditional validation — depends-on, optional-if-answered | Validators → |
sanitize | Normalises values before they are validated | Below ↓ |
toggleDisabled | Enables and disables submit buttons as the form becomes valid | Below ↓ |
jsconf | Declare rules in JavaScript instead of attributes | Below ↓ |
sweden | Personal identity numbers, phone numbers, counties, municipalities | Validators → |
uk | VAT number, National Insurance number, UTR | Validators → |
brazil | CPF, CEP, telephone | Validators → |
poland | PESEL, NIP, REGON | Validators → |
Module: native
Without this module the browser and the plugin hold two separate, contradictory opinions about
the same field: your rule says the value is wrong, while element.validity.valid
still reports true. The native module keeps them in agreement, in both
directions.
Results are mirrored onto the element. Every validation outcome is written
back with setCustomValidity(), so these all reflect your data-validation
rules:
$.validate({ modules: 'native' });
// After a failed check on #email:
document.querySelector('#email').validity.valid; // false
document.querySelector('#email').validationMessage; // your message
document.querySelector('form').checkValidity(); // false<!-- And the CSS pseudo-classes line up too -->
<style>
input:user-invalid { border-color: #b91c1c; }
input:user-valid { border-color: #15803d; }
</style>Constraints can be answered by the browser. Add
data-validation="native" to a field and ValidityState decides, rather
than a regular expression:
<input type="email" required data-validation="native">
<input type="number" min="10" max="20" step="2" data-validation="native">
To have the html5 module emit native for every field it recognises,
rather than translating attributes into the plugin's own rules, turn on
preferNativeValidation:
$.validate({
modules: 'html5, native',
preferNativeValidation: true
});Those pseudo-classes only match after the visitor has actually edited the field — that is the point of them, and why an untouched form never turns red on load. Scripted value changes will not trigger them.
Module: html5
Reads the HTML5 validation attributes already on your markup and turns them into plugin rules, so one set of attributes drives both.
| Recognised | Becomes |
|---|---|
required | required |
type="email" | email |
type="url" | url |
type="date" | date |
type="time" | time (loads the date module) |
type="number" with min/max/step | number with a matching allowing |
pattern | custom |
maxlength | length |
<input type="email" required maxlength="80">$.validate({ modules: 'html5' });Rule writing is idempotent, so a form scanned repeatedly — which is what happens with observeDynamicFields — keeps a single copy of each rule instead of accumulating duplicates.
Module: sanitize
Normalises a value before it is validated, and writes the cleaned value back into the field, so
what the user sees is what gets submitted. Declared with data-sanitize.
<input name="username" data-sanitize="trim lower" data-validation="length"
data-validation-length="min3">
<input name="title" data-sanitize="trim capitalize">
<input name="code" data-sanitize="upper trim">| Sanitizer | Effect |
|---|---|
trim | Removes whitespace from both ends. |
trimLeft / trimRight | Removes whitespace from one end. |
upper / lower | Changes case throughout. |
capitalize | Upper-cases the first letter of each word. |
insertLeft / insertRight | Prepends or appends text, from data-sanitize-insert-left / -right. |
escape | Converts < > & ' " to HTML entities. |
strip | Removes each word listed in data-sanitize-strip. |
numberFormat | Formats via numeral.js using data-sanitize-number-format. numeral is optional — without it, grouping characters are simply stripped. |
localeNumberFormat | Formats via Intl.NumberFormat, no third-party library. See Numbers. |
<input data-sanitize="localeNumberFormat"
data-sanitize-locale="de-DE"
data-sanitize-number-options='{"minimumFractionDigits":2}'>Module: toggleDisabled
Disables the form's submit buttons until every field validates, adding and removing a
disabled class alongside the attribute. It reacts to value changes, not only to
clicks.
$.validate({ modules: 'toggleDisabled' });A disabled submit button gives no explanation of what is wrong, and cannot be focused to find out. Letting the submit fail and showing an error summary is usually kinder, and is what the plugin does by default.
Module: jsconf
For markup that is not yours to change — a CMS, a third-party template — declare the rules in
JavaScript instead. $.setupValidation() applies them as attributes and then calls
$.validate() for you.
$.setupValidation({
form: '#my-form',
modules: 'security',
validate: {
// by name
'user': {validation: 'length', length: 'min4'},
'email': {validation: 'email'},
// by id
'#phone': {validation: 'required', 'error-msg': 'We need a number'},
// by class
'.postcode': {validation: 'required'}
}
});
Keys become data-validation-* attributes. Prefix a key with an underscore to set a
plain attribute instead:
'email': {validation: 'email', _placeholder: '[email protected]'}Writing a module
A module is a file that registers what it provides and then adds validators. Register the name so the loader knows not to fetch it twice.
(function ($) {
'use strict';
$.formUtils.registerLoadedModule('mycompany');
$.formUtils.addValidator({
name: 'employeeid',
validatorFunction: function (value) {
return /^EMP-\d{6}$/.test(value);
},
errorMessage: 'Employee IDs look like EMP-000123',
errorMessageKey: 'badEmployeeId'
});
})(jQuery);$.validate({ modules: 'mycompany' });
Keep the file beside the core script, or pass a path to loadModules(). See
custom validators for the full shape of a validator
object, including asynchronous ones.