Accessible jQuery Form Validation Plugin - ADA Validation

File Size: 122 KB
Views Total: 2658
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Accessible jQuery Form Validation Plugin - ADA Validation

ADA Validation is a jQuery based form validator that provides ADA compliant, client-side validation on existing form fields using REGEX, required, or custom validation functions.

Base validations included:

  • Password
  • Email
  • Phone
  • SSN
  • ZIP
  • Date
  • Credit Card Number (CCEXP, CCV)
  • Abartn
  • Required

Features:

  • Validation summary appears at the top of the page and includes jump links to the fields with errors. Each field is listed with specific information.
  • A simple statement appears at the top of the page letting the user know there are errors with the form. The message is more generic and actual issues are identified only at the field level.
  • Or no summary appears, instead focus is given to first field with an error.

Basic usage:

1. Download and include the jQuery ADA Validation plugin after jQuery JavaScript library.

<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="dist/jquery.ada-validate.js"></script>

2. Add a validation rule to your input field using data-validation attribute.

<input type="text" id="fname" name="fname" data-validation="fname" required>
<i class="validation-icon"></i>

3. Custom the validation rule.

$.extend(window.validations, {

  fname: {
    autocapitalize: true,
    maxlength: 15,
    rules: [
      {
        note: 'Enter only letters, hyphens, spaces, commas, periods and apostrophes',
        regx: /^[A-Za-z\-\s\.]+$/,
        minTestLen: 1
      },
    ]
  },

});

4. The required CSS styles for the form validatior.

.control-input {
   margin: 0 32px 0 0;
   position: relative;
}

.validation-icon {
  width: 28px;
  height: 28px;
  position: absolute;
  top: 0;
  right: -32px;
}

.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label {
    color: #8a6d3b;
}

.has-warning .form-control {
  border-color: #8a6d3b;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}

.has-warning .validation-icon {
  background: url(../images/validation-sprite.png) 0 -28px no-repeat;
}

.has-warning .form-control:focus {
  border-color: #66512c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;
}

.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label {
    color: #a94442;
}

.has-error .form-control {
  border-color: #a94442;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}

.has-error .form-control:focus {
  border-color: #843534;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;
}

.has-error .validation-icon {
  background: url(../images/validation-sprite.png) 0 -56px no-repeat;
}

.validations[aria-hidden="true"],
.validations [aria-hidden="true"] { 
  display: none;
}

.validations ul {
  list-style: none;
  margin: 5px 0;
  padding: 0;
}

.validations li {
  margin: 0 0 10px 0;
}
.validations li:last-child {
  margin: 0;
}

.validations {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}

.validations {
  width: auto;
  height: auto;
  overflow: visible;
  clip: inherit;

  margin: 7px 0 0;
  padding: 8px 12px;
  border: 1px solid #666;
  position: absolute;
  background: #fff;
  font-size: 1em;
  font-family: Helvetica,Arial,sans-serif;
  color: #666;
  text-shadow: 0 1px #fff;
  -webkit-background-clip: padding-box;
  -moz-background-clip: padding-box;
  background-clip: padding-box;
  -webkit-animation: showHide 300ms 0 ease;
  -moz-animation: showHide 300ms 0 ease;
  -ms-animation: showHide 300ms 0 ease;
  animation: showHide 300ms 0 ease;
  max-height: 20em;
  z-index: 3;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(0,0,0,.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(0,0,0,.6);
}

.validations:before {
  border-color: transparent transparent #666;
  border-style: dashed solid;
  border-width: 7px;
  position: absolute;
  left: 10px;
  top: -14px;
  z-index: 1;
  content: "";
}

.validations:after {
  border-color: transparent transparent #fff;
  border-style: dashed solid;
  border-width: 7px;
  position: absolute;
  left: 10px;
  top: -12px;
  z-index: 2;
  content: "";
}

.error-summary {
  display: none;
  border: 1px solid #666;
  padding: 10px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(0,0,0,.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(0,0,0,.6);
}

.error-summary.open {
  display: block;
}

5. Validate the form on submit.

$('#SUBMIT-BUTTON').validatedForm({
  summary: '#err',
  submits: false,
  container: '#form1',
  resetbtn: '#resetBtn',
  onSuccess: function () {
    console.log('Success', this);
  }
});

6. Base Validations. You can add new validations or overriding existing validations.

window.validations = {

  password: {

    // Text input maximum number of chars
    maxlength: 32,
    rules: [
      {
        note: 'Enter 8 to 32 characters',
        regx: /^.{8,32}$/
      },
      {
        note: 'Enter at least 1 letter and at least 1 number',
        regx: /^(?=.*\d)(?=.*[a-zA-Z]).+$/
      },
      {
        // 'requirement' or 'restriction' ('requirement')
        type: 'restriction',

        //  Error message to display
        note: 'Input must not contain the word "Password"',

        //  Single Regex or Array of Regexes (/.+/)
        regx: /[Pp]assword/
      }
    ]
  },

  email: {
    maxlength: 48,
    rules: [
      {
        note: 'Enter a proper email format (e.g., [email protected])'
      },
      {

        // Help will not trigger a warning or an error
        help: false,
        note: 'Enter a proper email format (e.g., [email protected])',
        regx: /^[\'_a-zA-Z0-9-]+(\.[\'_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,})$/,

        // Number of chars before validation takes place (-1)
        minTestLen: 1
      },
      {
        help: false,
        note: 'Input must contain "@" and "."',
        regx: /^(?=.*@)(?=.*\.).+$/,
        minTestLen: 5
      },
      {
        type: 'restriction',
        note: 'Input must not have more than 48 characters',
        regx: /^.{49,}$/,
      },
      {
        type: 'restriction',
        note: 'Input must not start or end with "@" and "."',
        regx: [
          /^@/,
          /@$/,
          /^\./,
          /\.$/
        ]
      },
      {
        type: 'restriction',
        note: 'Input must not contain more than one "@"',
        regx: /^[^@]*@[^@]*(?=@)/
      },
      {
        type: 'restriction',
        note: 'Input must not have "." immediately following "@"',
        regx: /@\./
      },
    ]
  },

  phone: {
    maxlength: 14,

    // Text input placeholder text
    placeholder: '(XXX) XXX-XXXX',
    rules: [
      {
        note: 'Enter 10 digits, no hyphens',
        regx: /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/
      },
      {
        type: 'restriction',
        note: 'Invalid Phone Number',

        // Can be used in place of 'regx' but not together.
        func: function(val) {
          var input = String(val.replace(/[^\d]/g, ''));
          if (input[0] === '0' || input[0] === '1') {
            return;
          }
          if (input.length >= 3 && input[1] === input[2]) {
            return;
          }
          if (input.length >= 4 && input[3] === '0' || input[3] === '1') {
            return;
          }
          if (input.length >= 6 && input[4] === '1' && input[5] === '1') {
            return;
          }
          if (input.length === 10 && '01234567890123456789'.indexOf(input) !== -1) {
            return;
          }
          if (input.length === 10 && '98765432109876543210'.indexOf(input) !== -1) {
            return;
          }

          switch (input) {
            case '0000000000':
            case '1111111111':
            case '2222222222':
            case '3333333333':
            case '4444444444':
            case '5555555555':
            case '6666666666':
            case '7777777777':
            case '8888888888':
            case '9999999999':
              return;
          }
          return true;
        }
      },
    ]
  },

  ssn: {
    maxlength: 11,
    placeholder: 'XXX-XX-XXXX',
    rules: [
      {
        note: 'Enter 9 digits',
        regx: [
          /^\d{9}$/,
          /^\d{3}-\d{2}-\d{4}$/
        ]
      }
    ]
  },

  ssn4: {
    maxlength: 4,
    placeholder: 'XXXX',
    rules: [
      {
        note: 'Enter 4 digits',
        regx: /^\d{4}$/
      }
    ]
  },

  zip: {
    maxlength: 5,
    placeholder: 'XXXXX',
    rules: [
      {
        note: 'Enter 5 digits',
        regx: /^\d{5}$/
      }
    ]
  },

  zip4: {
    maxlength: 9,
    placeholder: 'XXXXX-XXXX',
    rules: [
      {
        note: 'Enter 5 plus 4 digits',
        regx: [
          /^\d{5}$/,
          /^\d{5}-\d{4}$/
        ]
      }
    ]
  },

  date: {
    maxlength: 10,
    placeholder: 'mm/dd/yyyy',
    rules: [
      {
        note: 'Enter a proper date format (e.g., mm/dd/yyyy)',
        func: function checkEmail(val) {
          var dt, dstr, ustr;
          var dateWithSlashes = /^\d{2}\/\d{2}\/\d{4}$/;
          var dateWithDashes = /^\d{2}-\d{2}-\d{4}$/;
          if (!dateWithSlashes.test(val) && !dateWithDashes.test(val)) {
            return false;
          }
          dt = new Date(val);
          if (dt) {
            dstr = (('0' + (dt.getMonth() + 1)).slice(-2)).toString() +
                   (('0' + dt.getDate()).slice(-2)).toString() +
                   dt.getFullYear().toString();
            ustr = val.replace(/[^\d]/g, '').toString();
            return (dstr === ustr);
          }
          return false;
        }
      },
    ]
  },

  ccnum: {
    maxlength: 19,
    placeholder: 'XXXX-XXXX-XXXX-XXXX',
    rules: [
      {
        note: 'Enter 16 digits',
        regx: [
          /^\d{16}$/,
          /^\d{4}\s\d{4}\s\d{4}\s\d{4}$/,
          /^\d{4}-\d{4}-\d{4}-\d{4}$/
        ]
      },
      {
        note: 'Input is not a valid credit card number',
        func: function checkLuhn(val) {
          var newval = val.replace(/[^\d]/g, '');
          var numdigits = newval.length;
          var sum = 0;
          var parity = numdigits % 2;
          var digit;

          if (numdigits !== 16) {
            return false;
          }

          for (var i = 0; i < numdigits; i++) {
            digit = parseInt(newval.charAt(i), 10);
            if (i % 2 === parity) {
              digit *= 2;
            }
            if (digit > 9) {
              digit -= 9;
            }
            sum += digit;
          }
          return (sum % 10) === 0;
        }
      }
    ]
  },

  ccexp: {
    maxlength: 7,
    placeholder: 'mm/yyyy',
    rules: [
      {
        note: 'Enter a proper format (e.g., mm/yyyy)',
        regx: /^\d{2}\/\d{4}$/
      }
    ]
  },

  ccv: {
    maxlength: 3,
    rules: [
      {
        note: 'Enter the last 3 digits of the ID number on the back of your Credit Card',
        regx: /^\d{3}$/
      }
    ]
  },

  abartn: {
    maxlength: 9,
    rules: [
      {
        note: 'Enter a valid bank account routing number',
        func: function checkAba(val) {
          var n = 0;

          for (var i = 0; i < val.length; i += 3) {
            n += parseInt(val.charAt(i), 10) * 3 +
                 parseInt(val.charAt(i + 1), 10) * 7 +
                 parseInt(val.charAt(i + 2), 10);
          }

          return (n !== 0 && n % 10 === 0);
        }
      },
      {
        note: 'Enter 9 digits',
        regx: /^\d{9}$/
      }
    ]
  },

  required: {
    rules: [
      {
        help: false,
        note: 'Input is required',
        regx: /.+/,

        // Does this rule's note appear on first focus of input?
        showOnFirstFocus: false
      }
    ]
  }

};

Change log:

2016-02-03

  • bug fix. On iOS and Android when user clicked error summary links that were focusing on radio or checkbox inputs, they did not scroll page.

2015-12-10

  • Added custom required messages per field

This awesome jQuery plugin is developed by mcdpartners. For more Advanced Usages, please check the demo page or visit the official website.