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.

JavaScript
$.validate({
  modules: 'security, date, file'
});

If they live somewhere else, say so:

JavaScript
$.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.

JavaScript
import jQuery from 'jquery-form-validator';
import 'jquery-form-validator/modules/security';
import 'jquery-form-validator/modules/date';

jQuery.validate();
The two styles mix safely

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.

JavaScript
$.validate({
  modules: 'security',
  onModulesLoaded: function () {
    // Every named module has registered by this point.
  }
});
Module and rule names cannot contain a hyphen

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

ModuleAddsReference
securityPasswords, credit cards, CVV, breach screening, server-side checks, reCAPTCHA, spam checkValidators →
datetime and birthdateValidators →
fileFile size, MIME type, extension, image dimensions and ratioValidators →
locationCountries, federal states, longitude/latitude, plus suggestionsValidators →
sepaIBAN, BIC and SEPA membershipValidators →
colorhex, rgb, rgba, hsl, hslaValidators →
nativeThe Constraint Validation API bridgeBelow ↓
html5Translates HTML5 validation attributes into plugin rulesBelow ↓
logicConditional validation — depends-on, optional-if-answeredValidators →
sanitizeNormalises values before they are validatedBelow ↓
toggleDisabledEnables and disables submit buttons as the form becomes validBelow ↓
jsconfDeclare rules in JavaScript instead of attributesBelow ↓
swedenPersonal identity numbers, phone numbers, counties, municipalitiesValidators →
ukVAT number, National Insurance number, UTRValidators →
brazilCPF, CEP, telephoneValidators →
polandPESEL, NIP, REGONValidators →

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:

JavaScript
$.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
HTML
<!-- 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:

HTML
<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:

JavaScript
$.validate({
  modules: 'html5, native',
  preferNativeValidation: true
});
:user-invalid needs real interaction

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.

RecognisedBecomes
requiredrequired
type="email"email
type="url"url
type="date"date
type="time"time (loads the date module)
type="number" with min/max/stepnumber with a matching allowing
patterncustom
maxlengthlength
HTML
<input type="email" required maxlength="80">
JavaScript
$.validate({ modules: 'html5' });
Re-scanning is safe

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.

HTML
<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">
SanitizerEffect
trimRemoves whitespace from both ends.
trimLeft / trimRightRemoves whitespace from one end.
upper / lowerChanges case throughout.
capitalizeUpper-cases the first letter of each word.
insertLeft / insertRightPrepends or appends text, from data-sanitize-insert-left / -right.
escapeConverts < > & ' " to HTML entities.
stripRemoves each word listed in data-sanitize-strip.
numberFormatFormats via numeral.js using data-sanitize-number-format. numeral is optional — without it, grouping characters are simply stripped.
localeNumberFormatFormats via Intl.NumberFormat, no third-party library. See Numbers.
HTML
<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.

JavaScript
$.validate({ modules: 'toggleDisabled' });
Consider whether you want this

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.

JavaScript
$.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:

JavaScript
'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.

form-validator/mycompany.js
(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);
JavaScript
$.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.