JS Components

f-validate – Form Validation Module

The f-validation module is used to add client-side validation to a form.

The module aims to use the default HTML5 form validation attrbutes wherever possible and extend this with it's own rules for more specific validation checks.

For example, if an input within a form passed to f-validate has a type of email set, the module will apply the email validation rule to that field.

Usage

To setup f-validate, you first need to install the module using Yarn or NPM.

yarn add @justeat/f-validate

Then within your JavaScript, import the module:

import Validate from '@justeat/f-validate';

Once you have imported the module, you can then attach f-validate to a form. To do this, you can either pass in the name of your form or the form element itself, such that:

// 1. Pass in the name of the form to be validated
new FormValidation('formName');


// 2. Pass in the form element to be validated
const myForm = document.querySelector('.myForm');
new FormValidation(myForm);

Once you have done this, f-validate will automatically validate the form based on the HTML5 form attributes set on each field (such as required) or by checking whether a field has the specified rule data-attribute set on it. For more information on how to specify rules, see the Validation Rules section below.


Validation Rules

f-validate aims to use the default HTML5 form validation attrbutes wherever possible. For example, if an input has a type of email, it will apply the email validation test to it.

The following rules are currently available within the validation module to apply to fields.

Required

Valid field types = input | select | textarea | radio | checkbox
Default Error Message = 'This field is required.'


This rule checks that a value is present for the field being validated.

To validate a field with this rule, either set the required HTML5 attribute or add the data-val-required attribute to the field:

// via required attribute
<input type="text" required />

// via data-val-required attribute
<input type="text" data-val-required />

When set on an input, select or textarea field, a value must be present for this rule to pass validation.

For fields of type checkbox, this rule checks that the field has been checked and for fields of type radio, this rule will validate as true as long as one radio button with the same name attribute has been selected.

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <label>Name:
                <input type="text" required>
            </label>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Email

Valid field type = input
Default Error Message = 'This field must contain a valid email address.'


This rule checks that the value of the field being validated is a valid email address.

To validate a field with this rule, set its type such that type="email".

<input type="email" />

This rule uses the following regular expression to validate email addresses:

/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <label>Email:
                <input type="email">
            </label>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Minlength

Valid field types = input | textarea
Default Error Message = 'This field must be at least {0} characters in length.'


This rule checks that the value of the field is of a specified minimum length. Note that it doesn't check if a value has been entered (like the required rule), simply that if a value has been entered by the user, then it should be at least x characters in length.

It can be applied to input and textarea fields.

To validate a field with this rule, eiher set the minlength attribute or add the data-val-minlength attribute to the field:

// via minlength attribute
<input type="text" minlength="5" />

// via data-val-minlength attribute
<input type="text" data-val-minlength="5" />

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <label>Name (minimum 5 characters):
                <input type="text" minlength="5">
            </label>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Maxlength

Valid field types = input | textarea
Default Error Message = 'This field must not exceed {0} characters in length.',


This rule checks that the value of the field is no greater than the specified maximum length.

To validate a field with this rule, eiher set the maxlength attribute or add the data-val-minlength attribute to the field:

// via maxlength attribute
<input type="text" maxlength="20" />

// via data-val-maxlength attribute
<input type="text" data-val-maxlength="20" />

Note that when using the maxlength attribute, most modern browsers will stop the user entering more than the number of characters specified.

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <label>Name (maximum 5 characters):
                <input type="text" maxlength="5">
            </label>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Pattern

Valid field types = input | textarea
Default Error Message = 'This field contains a value that isn’t accepted.'


This rule checks that the value of the field matches the regular expression specified. The pattern must match the entire value and not just some subset.

To validate a field with this rule, eiher set the pattern attribute or add the data-val-regex attribute to the field:

// via pattern attribute
<input type="text" pattern="[a-z]{1,6}" />

// via data-val-maxlength attribute
<input type="text" data-val-regex="[a-z]{1,6}" />

It's considered best practice to set the title attribute when validating with this rule to describe the pattern to help the user.

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <label>Pattern (Valid pattern = a string of 1-6 letters):
                <input type="text" pattern="[a-z]{1,6}">
            </label>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Matches

Valid field type = input
Default Error Message = 'This field does not match the {0} field.'


This rule checks that the value of the field being validated matches the value of a separate specified field. To be valid it must match the entire value and not just some subset.

To validate a field with this rule, set the data-val-equalto attribute to the field:

// via data-val-maxlength attribute
<input type="text" data-val-equalto="matchedField" />

// note that a field with the name passed should exist, or the rule will always fail
<input type="text" name="matchedField" />

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <ul class="u-unstyled">
                <li>
                    <label>First field
                        <input type="text" required data-val-equalto="fieldTwo">
                    </label>
                </li>
                <li>
                    <label>Second field
                        <input type="text" name="fieldTwo">
                    </label>
                </li>
            </ul>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Date In Future

Valid field type = select
Default Error Message = 'This date must be in the future.'


This rule is for validating dates entered by a collection of select fields. When applied to a group of fields, it returns true if the date entered in these fields is in the future.

Currently, this rule only validates dates specified with a month and year and has not yet been extended to test for day.

To validate a group with this rule, set the data-val-group and data-val-dateinfuture attributes on the container wrapping the select fields.

Then apply the data-val-dateinfuture-type="month" and data-val-dateinfuture-type="year" attributes to eachselect` field, such that:

// Apply `data-val-dateinfuture` attribute to the outer container
<div data-val-group data-val-dateinfuture>
    // Apply `data-val-dateinfuture-type` attributes to the relevant `select` fields
    <select data-val-dateinfuture-type="year">
        <option value="" ></option>
        <option value="2018"></option>
    </select>
    <select data-val-dateinfuture-type="month">
        <option value="" ></option>
        <option value="01"></option>
    </select>
</div>

Example

<div class="g">
    <div class="g-col g-span4">
        <form name="test-form">
            <div data-val-group data-val-dateinfuture>
                <select data-val-dateinfuture-type="year">
                    <option value="" ></option>
                    <option value="2017">2017</option>
                    <option value="2018">2018</option>
                    <option value="2019">2019</option>
                    <option value="2020">2020</option>
                </select>
                <select data-val-dateinfuture-type="month">
                    <option value="" ></option>
                    <option value="01">01</option>
                    <option value="02">02</option>
                    <option value="03">03</option>
                    <option value="04">04</option>
                    <option value="05">05</option>
                    <option value="06">06</option>
                    <option value="07">07</option>
                    <option value="08">08</option>
                    <option value="09">09</option>
                    <option value="10">10</option>
                    <option value="11">11</option>
                    <option value="12">12</option>
                </select>
            </div>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Conditional Required

Valid field type = input
Default Error Message = 'This field is required.'


This validation rule checks that if a specified checkbox is not checked, then it is required that a value must be entered in the field with this validation check.

This also means that if the specified checkbox is checked, then the field is not required and the form will return valid when the field is empty.

To validate a field with this rule, set the data-val-conditionalrequired attribute on the field to be validated, passing in the name of the checkbox to validate against:

// via `data-val-conditionalrequired` attribute
<input type="text" data-val-conditionalrequired="nameOfcheckedInput" />
// the checkbox to test against
<input type="checkbox" name="nameOfcheckedInput" />

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <ul class="u-unstyled">
                <li>
                    <label>Name:
                        <input type="text" data-val-conditionalrequired="nameOfcheckedInput" />
                    </label>
                </li>
                <li>
                    <label>If this isn't checked, then the name field is required:
                        <input type="checkbox" name="nameOfcheckedInput" />
                    </label>
                </li>
            </ul>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Custom

Valid field type = All
Default Error Message = 'Custom validation failed.'


This validation rule allows the addition of a custom validation check to be added to the field.

To validate a field with a custom rule, you need to first set the data-val-custom attribute with the name of the function you want to call when the form is submitted.

You should then ensure that a data-val-custom-error attribute has been set with your custom error message.

// Apply data attributes to your field
<form name="myForm">
    <input data-val-custom="customRule" data-val-custom-error="The value entered does not match 'passTest'" />
</form>

Then in the JavaScript, after you have initialised f-validate on your form, you should pass in the custom validation function, using the addCustomValidation method, such that:

const validateForm = new Validate('myForm');

// Pass in a custom validation function
// This function will receive the field being validated
validateForm.addCustomValidation('customRule', field => {
    if (field.value === 'passTest') {
        return true;
    }
    return false;
});

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <input data-val-custom="customRule" data-custom-error="The value entered does not match 'passTest'" />
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Rule table

Rule Fields Hooks
Required

input

select

textarea

radio

checkbox

required | data-val-required
Email

input

type="email"
Minlength

input | textarea

minlength | data-val-minlength
Maxlength

input | textarea

maxlength | data-val-maxlength
Pattern

input | textarea

pattern | data-val-regex
Matches

input | textarea

data-val-equalto
Date In Future

select

Multiple (see example)
Conditional Required

input

data-val-conditionalRequired

Custom Error Messages

It's common to want to customise the messages displayed when certain fields aren't valid. To do this, you can define a data attribute specific to the validation rule you want the message to apply for, such that data-val-{validation-rule}-error.

For example:

// To replace the default error message when using the `required` validation rule
// set `data-val-required-error` to the message you would like to display
<input type="text" required data-val-required-error="This is my new required error message" />

// Similarly for other validation rules
// email:
<input type="email" data-val-email-error="This is my new email error message" />

// minlength:
<input type="text" minlength="5" data-val-minlength-error="This is my new minlength error message" />

// maxlength:
<input type="text" maxlength="5" data-val-maxlength-error="This is my new maxlength error message" />

// pattern:
<input type="text" pattern="[a-z]{1,6}" data-val-pattern-error="This is my new pattern error message" />

// matches:
<input type="text" matches="fieldToMatch" data-val-matches-error="This is my new matches error message" />

// conditionalrequired:
<input type="text" data-val-conditionalrequired="nameOfcheckedInput" data-val-conditionalrequired-error="This is my new matches error message" />

// for dateInFuture, apply the `data-val-dateinfuture` to the outer container
<div data-val-group data-val-dateinfuture data-val-dateinfuture-error="This is my new dateInFuture error message">

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <ul class="u-unstyled">
                <li>
                    <label>Name:
                        <input type="text" data-val-required data-val-required-error="This is a custom required error message" />
                    </label>
                </li>
            </ul>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Options

f-validate has a number of options that allow you to customise its functionality.

The properties or attributes that can be defined are as follows:

Setting Type Values Description
errorClass string String | has-error(default) Defines the class applied to each field when they fail validation. By default, the class added is `has-error`.
successClass string String | has-success(default) Defines the class applied to each field when they pass validation. By default, the class added is `has-success`.
groupErrorPlacement string bottom | top | Selector

When set, error messages will be grouped together rather than placed adjacent to each field.

If this value is set to `bottom`, then the error messages will be grouped at the bottom of the form.

If this value is set to `top`, then the error messages will be grouped at the top of the form.

If this value is set as a selector such as `.myClassName` or `[type="submit"]`, then the error messages will be grouped above the element matched in that selector. If this element isn't found, then it will group error messages as if the `top` value had been specified.

enableHTML5Validation boolean true | false (default)

Sets whether the `novalidate` attribute is added to the form being validated.

By default, `novalidate` is added to a form that is being validated to supress native HTML5 validation. By setting this option to `true` this attribute is not set and native HTML5 validation will not be supressed.

hybridMode boolean true | false (default)

When set, both blur (focus lost) and keydown events are bound to each applicable input field.

Validation won't run until the user has blurred the input at least once, giving them a chance to enter a valid value before seeing an error.

Grouped Error Messages

Sometimes, rather than display one error per field, you may want to display all of the forms validation messages together as a group.

To do this, you will need to specify the groupErrorPlacement option when you initialise f-validate.

new FormValidation(nameOfForm, {
    groupErrorPlacement: 'bottom'
});

To see all possible options that groupErrorPlacement accepts, check the options section of the documentation.

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form-group">
            <ul class="u-unstyled">
                <li>
                    <label>Name:
                        <input type="text" data-val-required data-val-required-error="This is a custom required error message" />
                    </label>
                </li>
                <li>
                    <label>Email:
                        <input type="email" data-val-email-error="This is a custom email error message" />
                    </label>
                </li>
                <li>
                    <label>Postcode:
                        <input type="text" pattern="[a-z]{0-6}" data-val-pattern-error="This is a custom pattern error message" />
                    </label>
                </li>
            </ul>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Applying Multiple Rules

To apply multiple rules to the same field, you simply need to add multiple attributes to define the rules you want to validate.

// To make a field validate as required and of type email
<input type="email" required />

// To make a field validate as minlength and maxlength
<input type="text"
    data-val-minlength
    data-val-maxlength
    data-val-minlength-error="Custom error minlength"
    data-val-maxlength-error="Custom error maxlength" />

Example

<div class="g g--alignCenter">
    <div class="g-col g-span6">
        <form name="test-form">
            <ul class="u-unstyled">
                <li>
                    <label>Name:
                        <input type="text"
                            data-val-minlength="2"
                            data-val-maxlength="5"
                            data-val-minlength-error="Name should be at least 2 characters long"
                            data-val-maxlength-error="Name should be a maximum of 5 characters long" />
                    </label>
                </li>
                <li>
                    <label>Email:
                        <input type="email" required />
                    </label>
                </li>
            </ul>
            <button type="submit" class="o-btn o-btn--primary o-btn--block">Submit</button>
        </form>
    </div>
</div>

Callback events

f-validate has a number of events you can hook into. These can be setup by proving a callback function in the options object. Examples of this are show below:

new FormValidation(nameOfForm, {
    onSuccess: function() {
        console.log("Great success!");
    },
    onError: function() {
        console.log("Form validation failed");
    },
    onElementError: function(element, validationType) {
        console.log(`The ${element.name} element failed the ${validationType} validator`);
    }
});
Event Description Parameters
onSuccess Fired after the entire form is validated and is considered valid. None
onError Fired after the entire form is validated and considered invalid. None
onElementError Fired after an individual form element fails a validation check
  • element – the DOM element that failed the validation checkbox
  • validationType – the name of the validation check that failed