Yup conditional validations for different scenarios but the same form

ยท

3 min read

Creating a form with validation can be a daunting task, especially when the validation rules change depending on different scenarios.

In this blog post, we will discuss how to implement conditional validation using Yup, a powerful validation library, along with React Hook Forms and Material UI.

Conditional Validation using the when() function

Suppose we have a form with 3 fields, "Loan Option", "Loan Amount" and "Loan Down Payment". We want to validate the amount field differently based on the loan option.

For example, if the user selects a car loan, we want to make sure that amount has a maximum value of 5000. On the other hand, if the user selects a mortgage loan, we want to make sure that the value is between 15 000 and 300 000.

We'll start with a basic Yup schema for our form:

import * as yup from 'yup';

const schema = yup.object().shape({
  loan: yup.string().typeError("You must select a loan").required(),
  amount: yup
    .number()
    .typeError("You must specify a number")
    .when("loan", {
      is: "mortgage",
      then: (schema) => schema.min(15000).max(300000).required(),
      otherwise: (schema) => schema.max(5000).required()
    }),
  downPayment: yup.number().nullable()
});

Here, we use the when() function to check the value of the loan field.

If the value of loan is mortgage, the amount field will be checked to have a value between 15 000 and 300 000. Otherwise, the amount field will be checked for a max value of 5000.

You can play around with this demo:

Custom Validation using the test() function

Now if we want the spice up a bit, imagine we have a complex scenario with 3 or more use cases ๐Ÿ˜จ

Yup also provides a test() function that allows us to define custom validation rules for a field. This function takes two arguments: a name for the test and a validation function.

For example, suppose we want to add a custom validation rule that checks if the downpayment is min 25 for the mortgage loan (1st) or if is at least 15% for a car loan (the 2nd scenario) and if the user selects a shopping loan (our 3rd scenario) we'll have the min value for 5%.

We can add the following code to our schema:

const schema = yup.object().shape({
...
  downPayment: yup
    .number()
    .typeError("You must specify a number")
    .test(
      "downpayment-test",
      "downpayment must respect the selected loan limits",
      (value, validationContext) => {
        const {
          createError,
          parent: { loan }
        } = validationContext;

        if (!value) {
          return createError({
            message: "The downpayment field is required"
          });
        }

        if (loan === "Mortgage Loan") {
          return value >= 25 && value < 100;
        }

        if (loan === "Car Loan") {
          return value >= 15 && value < 100;
        }

        if (loan === "Shopping Loan") {
          return value >= 5 && value < 100;
        }
      }
    )
...
})

I created a get wild demo ๐Ÿ˜„ that covers some scenarios like the ones mentioned:

As you imagine, sky is the limit ๐Ÿš€

Conclusion

In this blog post, we discussed how to implement conditional validation using Yup, React Hook Forms, and Material UI.

We used the when() and test() functions from Yup to change the validation logic applied to a field based on some conditions.

With this technique, we can create flexible and reusable forms that can handle different scenarios with ease.

References:

ย