Validate multiple fields using yup.

August 25, 2021.

Written by Thomas Duffy

multiple input validation with yup image

Intro

I started using yup for some basic form/data validation, and so far, it has been an excellent experience. Recently, I ran into an issue when validating multiple input fields. Yup would validate each field until it ran into a failure, leaving the fields below it unvalidated. Hopefully, this post will help anyone struggling with getting yup to validate all the data fields before throwing the error. Let’s get started.

Problem

Below is an image of the validation issue I’m describing above.

fields left not validated

Code for the validation above.

function validateForm(data) {
  return object()
    .shape({
      first_name: string().required(),
      last_name: string().required(),
      web_address: string().required(),
      email: string()
        .email()
        .required(),
    })
    .validate(data);
}

While this may be useful for some scenarios, it creates a weird user experience. Not having all the errors surfaced at once forces the user to correct each validation error one at a time, which in this use case is not ideal.

Intended behavior

The intended behavior I was looking for is to have yup continue validating the form or data fields even if there are validation failures. Below is an example of what I’m talking about.

validated multiple fields with yup image

Solution

So there are a couple of different ways to validate data in Yup. Below, I’m using the validate method, which throws a validation error that looks like this.

ValidationError = {
  name: 'ValidationError',
  path: 'first_name',
  errors: ['first_name is a required field' ]
  inner: []
}

This error above is what you use to show the user what field needs to be corrected in your form. The path property will match the scheme property you passed in.

The validate method takes in two parameters. validate(value, options). The value is the data you’re passing in to validate against the schema you defined.

The options param has the following options.

Options = {
  strict: boolean = false;
  abortEarly: boolean = true;
  stripUnknown: boolean = false;
  recursive: boolean = true;
  context?: object;
}

Notice the abortEarly property is defaulted to true. This is where the problem is. If you don’t pass an options object into validate, Yup will abort out of the validation chain, leaving your form/data partially validated. So the fix is simple, pass in an options object like the one below.

validate(data, { abortEarly: false });

So a full example would like this.

function validateForm(data) {
  return object()
    .shape({
      first_name: string().required(),
      last_name: string().required(),
      web_address: string().required(),
      email: string()
        .email()
        .required(),
    })
    .validate(data, { abortEarly: false });
}

Now, if you look at the ValidationError, you’ll see this.

ValidationError = {
  name: 'ValidationError',
  errors: ['first_name is a required field', 'last_name is a required field'],
  inner: [ValidationError, ValidationError],
};

Notice that the inner property and error property have all the errors from the form. You can now iterate over them and let the user know what fields need to be validated on the first submission! If you would like to see a complete working example of the solution above, you can take a look here.

Conclusion

So that is how you set up yup to validate your whole form instead of one field at a time. If you liked this post, please sign up for my newsletter to get notified of when I post some more articles!


Written by Thomas Duffy

Want to Build animations like the one above?

Sign up and get notified when I release my mini course on building animations with React.