HTML5 form validation helpers
Switch branches/tags
Nothing to show
Clone or download
Latest commit 9d4046b Aug 1, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
dist Update built files Aug 1, 2018
site Padding in mobile Feb 20, 2018
src Move `customError` to the last index in the list to be checked as las… Aug 1, 2018
.babelrc Initial Feb 19, 2018
.eslintignore Initial Feb 19, 2018
.eslintrc.js Initial Feb 19, 2018
.gitignore package lock Feb 20, 2018
.npmignore npmignore Feb 20, 2018
CNAME Create CNAME Feb 20, 2018
README.md Use yarn in the readme Jun 15, 2018
index-browser.js Build for web Feb 19, 2018
index.html Update the example page Feb 20, 2018
index.js Build for web Feb 19, 2018
package.json 1.1.1 Aug 1, 2018
yarn.lock Use yarn yay Jun 15, 2018

README.md

ValidForm

ValidForm is a thin JavaScript wrapper on the HTML5 Form Validation features. It is very small at about 200 lines of code (7k, 5.6k compressed), and it has no dependencies. Nope, none.

For background, check out the blog post that lead to this module.

The HTML5 form validation features are pretty good, but have a couple warts. ValidForm is a layer on the HTML5 features and attempts to augment them with three things:

  1. An invalid class on inputs when they are invalid. This class provides better user feedback than the :input pseudo selector.
  2. Support for displaying custom messages by way of HTML attributes or an object on initialization.
  3. Validation error messages are displayed in a custom div.

What does it look like (with custom styles)?

screen shot 2018-02-19 at 1 49 08 pm

Try it out →

Installing

Without npm / yarn

If you just want to include a script in an HTML file, you can find the valid-form.js and valid-form.min.js in the dist folder.

There will be a ValidForm global.

So you can call ValidForm(formElement, options). Other functions exposed will be properties on ValidForm. For example, ValidForm.handleCustomMessageDisplay(input, options)

And usage:

<script>
  var formElement = document.querySelector('form')
  ValidForm(formElement)
</script>

With npm / yarn / webpack

npm install @pageclip/valid-form
# or
yarn add @pageclip/valid-form

(Apologies for the scoped package. NPM is annoying)

Then import it like so:

import ValidForm from '@pageclip/valid-form'
const formElement = document.querySelector('form')
ValidForm(formElement)

Or import the other exposed functions if you want to:

import {
  toggleInvalidClass,
  handleCustomMessages,
  handleCustomMessageDisplay
} from '@pageclip/valid-form'

Usage

For the tl;dr, check out the example code, and see it in action.

The main function is ValidForm() which you call with a <form> element.

const formElement = document.querySelector('form')
ValidForm(formElement, options) // options optional

It will hook the invalid and input events for <input>, <select>, and <textarea> elements.

You can use any HTML5 validation attributes on these inputs and ValidForm will display the same things you would get with raw HTML5 form validation. e.g. required, pattern, type, etc.

<form method="post" action="/">
  <div class="form-group">
    <input required type="email" pattern="[ab]+@.+" />
  </div>

  <div class="form-group">
    <select required>
      <option value="">pick one!</option>
      <option value="cat">Cat</option>
      <option value="dog">Dog</option>
      <option value="catdog">Catdog</option>
    </select>
  </div>

  <div class="form-group">
    <textarea required pattern="[ab ]+"></textarea>
  </div>
</form>

CSS styles are not provided by ValidForm, so you will need to do your thing. Fortunately, the amount of CSS required is small.

As an example, if you are using bootstrap and all the ValidForm defaults, here is how to recreate the example in the image at the top of this readme.

/*
  Style the input itself when it is invalid
*/
.form-control.invalid {
  border-color: red;
}

/*
  Style the validation errors.

  By default, `ValidForm` inserts the `.validation-error` div
  _before_ the input. So we abs position in the top right.

  Why insert before? It is nicer on the user than inserting
  after the input and moving elements down the page.
*/
.form-group {
  position: relative;
}
.form-group .validation-error {
  position: absolute;
  right: 0;
  top: 1px;

  color: red;
  font-size: 14px;
}

The invalid Class

The :invalid pseudo selector built into the browser isn't very good. If your input is required and empty on page load, :invalid is true. If you style :invalid with, say, a red border, all required fields will be red on page load. Kinda dumb.

The invalid class is added only after the user submits the form, then stays until the user fixes the input. An example of what it will generate:

<form method="post" action="/">
  <div class="form-group">
    <!-- invalid class added by ValidForm -->
    <input required class="invalid" type="email" pattern="[ab]+@.+" />
  </div>
</form>

And you can style it like so

.invalid {
  border-color: red;
}

The class name is configurable in options.

Custom Messages

Custom messages can be specified in 2 ways:

  1. As attributes on the input
  2. In a customMessages object on the options to ValidForm()

Naming of these is based on the ValidityState object provided by the browser. For attributes, prepend a data-, for the options object use them as is.

Specifying as attributes:

  <form method="post" action="/">
    <input
      required
      type="email"
      pattern="[ab]+@.+"
      data-valueMissing="Enter something, plz"
      data-patternMismatch="Just give me a's and b's"
      data-rangeOverflow="Number too low!"
      data-rangeUnderflow="Number too high!"
      data-stepMismatch="Step doesn't fit into my notches!"
      data-tooLong="Text is too long"
      data-tooShort="Text is too short"
      data-typeMismatch="Hey, this isn't an email"
      data-badInput="Something bad happened"
      />
    </form>

Specifying as an object:

const formElement = document.querySelector('form')
ValidForm(formElement, {
  customMessages: {
    valueMissing: "Enter something, plz",
    patternMismatch: "Just give me a's and b's",
    rangeOverflow: "Number too low!",
    rangeUnderflow: "Number too high!",
    stepMismatch: "Step doesn't fit into my notches!",
    tooLong: "Text is too long",
    tooShort: "Text is too short",
    typeMismatch: "Hey, this isn't the correct type",
    badInput: "Something bad happened"

    // Special mismatches for different input types: `${type}Mismatch`
    emailMismatch: "Hey, this isn't an email",
    urlMismatch: "Not a URL :(",
    numberMismatch: "Nope, not a number!",
  }
})

Attributes take precedence over the object. So you can provide blanket custom messages with the customMessages object, then override with any input specific messages as attributes on the input.

Custom Message Display

When there is an invalid input, ValidForm will do 2 things:

  1. Insert a message <div class="validation-error" /> either before (default) or after the input. Placement and classname are configurable.
  2. Add a class (has-validation-error is default) to the input's parent element.

When the user fixes the error, the message div and the parent class will be removed.

An example of the markup when there is an error:

<form method="post" action="/">
  <div class="form-group has-validation-error">
    <div class="validation-error">Oops, there was an error!</div>
    <input required class="invalid" type="email" pattern="[ab]+@.+" />
  </div>
</form>

API

ValidForm(element, options)

The main function, and the one you should probably use. e.g.

const formElement = document.querySelector('form')
ValidForm(formElement, {
  invalidClass: 'form-input_invalid',
  errorPlacement: 'after',
  customMessages: {
    valueMissing: 'Enter something tho.'
  }
})
  • element - Can be a <form>, <input>, <select>, or <textarea> element. It will throw an error if anything else. When it is a form, it will properly focus the first invalid input on submission.
  • options - (optional) Object
    • invalidClass - (default: 'invalid') Class applied to input when invalid
    • validationErrorClass - (default: 'validation-error') Class applied to error message <div> when there is a validation error,
    • validationErrorParentClass - (default: 'has-validation-error') Class applied to ,
    • errorPlacement - (default: 'before') Where to insert the error message node. It can be 'before' or 'after'
    • customMessages - (default: {}) See custom messages section. When nothing is specified, and for any non-specified message, the browser-default messages will be shown.

ValidForm() calls all the following functions. If you want super custom behavior, you can use the following 3 functions.

toggleInvalidClass(input, invalidClass)

Hooks the input and invalid events on an input.

  • input - A <input>, <select>, or <textarea> element.
  • invalidClass - String class to be applied to input when invalid

handleCustomMessages(input, customMessages)

Deals with showing custom messages.

  • input - A <input>, <select>, or <textarea> element.
  • customMessages - (default: {}) See custom messages section. When nothing is specified, and for any non-specified message, the browser-default messages will be shown.

handleCustomMessageDisplay(input, options)

Shows validation messages in a custom div when there is a validation error.

  • input - A <input>, <select>, or <textarea> element.
  • options - (optional) Object
    • validationErrorClass - (default: 'validation-error') Class applied to error message <div> when there is a validation error,
    • validationErrorParentClass - (default: 'has-validation-error') Class applied to ,
    • errorPlacement - (default: 'before') Where to insert the error message node. It can be 'before' or 'after'

Developing

Write code in src, yo.

yarn install
yarn build # build all the js
yarn site  # run the example site

The site is available at http://localhost:8080.

License

MIT