Skip to content

Instantly share code, notes, and snippets.

@samsch
Last active July 11, 2017 13:55
Show Gist options
  • Save samsch/fdc503902a66a7b577420b29bcdac843 to your computer and use it in GitHub Desktop.
Save samsch/fdc503902a66a7b577420b29bcdac843 to your computer and use it in GitHub Desktop.
How to implement validation in a React based form.

How to implement validation in a React based form

Data and app structure

The data structure for the form should be something like:

{
  field1: "value1",
  field2: "value2",
}

Where you have a set of field properties and values that are being rendered into your form. The rendering of the form fields doesn't need to be changed for validation directly at all with this approach.

How validation works

At some point before or at the start of render (for Redux, ideally in a selector), you call a memoized validation function with your form state as it's argument. This memoized function has an output with similar structure to your form state, but instead of values for each field, you return the validation results. These results could be just strings, arrays, or objects, depending on how complex the individual validation per field is.

Validation function example

A fairly performant approach for this validation function is like this:

const checkField1 = memoize(function(value) {
  return value && value.search(/^[\d]*&/) !== -1 ? true : 'Please enter an integer';
});

//More functions like checkField2, etc.

const validate = memoize(function(formState) {
  return {
    field1: checkField1(formState.field1),
    field2: checkField2(formState.field2),
    //...
  }
});

You then additionally render validation messages after each field (or with, or at the bottom of the form, since the approach is fairly agnostic to how you render). A simple render (which matches the above checkField1) might look like this:

<form>
  ...
  <label>
    Enter a number between 1 and 100: <input type="text" />
  </label>
  {validation.field1 === true ? null : <div className="field-error">{validation.field1}</div>}
  ...
</form>

Blocking submission on invalid fields

If you need to block form submission unless you have only valid fields, there are a couple possiblities. One is to create the form in a function or variable before render returns, and within that rendering you can clear/set a flag if a field is invalid. Then in your render of the form, you can check the flag whether subission goes through. Another approach is to check the validation object on form submit. This requires that the validation function happens outside of render, such as in a (react-redux connect()) selector, or a parent component. The check is a simple as looping over the properties with Object.keys(validation).reduce() and in the reduce function checking each field and returning a valid/invalid flag.

Highlighting invalid fields

To highlight the invalid fields, you can render them with a class (such as invalid), then on bad submit, you add a class to the form (like highlight), and then removed it after a short time.

To implement this, you can use setState on an invalid submit to set a flag, and start a setTimeout which then runs setState to clear the flag. In render, when the flag is set, you add the class to the form. The CSS to go along with this could be something like:

.form-namespace .highlight .invalid {
  outline: 2px solid red;
}

You could of course make this much fancier, with a transition in/out, or whatever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment