Search code examples
next.jsreact-hook-formzod

How to implement conditional validation in Zod for a file input field based on a radio button selection?


I'm currently working on a form validation using Zod with react hook forms, and I'm facing a challenge with implementing conditional validation for a file input field based on the selection of a radio button.

Here's a simplified version of my code:

const formScheme = z.object({
  businessType: z.enum(["PVT Ltd", "Partnership", "Sole Proprietor"], { required_error: 'Business Type is required.' }),
  form120: z
    .any()
    .optional()
    .refine(file => file.length == 1 ? file[0]?.type === 'application/pdf' ? true : false : true, 'Must be a PDF.')
    .refine(file => file.length == 1 ? file[0]?.size <= 3000000 ? true : false : true, 'Max file size is 3MB.'),
})

I want to make the form120 field required only if the businessType is "PVT Ltd". In other words, if the user selects "PVT Ltd" as the business type, they must also upload a file using the form120 field.

I've tried a few things, but I'm not sure how to conditionally require the form120 field based on the businessType. Any suggestions or examples on how to achieve this with Zod would be greatly appreciated.

Thanks in advance!


Solution

  • After some exploration, I've come up with a solution to address the conditional validation challenge using Zod with React Hook Forms. If you need to make the form120 field required only when the businessType is "PVT Ltd" you can achieve this with the discriminated union.

    export const unionSchema = z.discriminatedUnion("businessType", [
      z.object({
        businessType: z.literal("PVT Ltd"),
        form120: z
          .any()
          .refine((file) => file?.length == 1, 'Form 1/20 is required for PVT Ltd business.')
          .refine((file) => file[0]?.type === 'application/pdf', 'Must be a PDF.')
          .refine((file) => file[0]?.size <= 5000000, `Max file size is 5MB.`),
      }),
      z.object({
        businessType: z.literal("Partnership"),
      }),
      z.object({
        businessType: z.literal("Sole Proprietor"),
      }),
    ]).and(formSchema)
    

    In this schema, I've used z.discriminatedUnion to handle different validation rules based on the businessType. If the businessType is "PVT Ltd" it enforces specific validation rules for the form120 field, making it required and imposing certain file criteria. For other business types like "Partnership" and "Sole Proprietor," no additional validations are applied.