skip to Main Content

I’m working on a React Native project where I’m using React Hook Form for a dynamic form, along with Valibot for validation. I have a scenario where I need to hide some input fields based on certain conditions. However, these fields are also required under specific conditions.

I’ve tried using register and unregister to handle this, but it doesn’t seem to work as expected. When I hide the input, I don’t want it to be validated, but when it’s visible, it should be required.

Can anyone guide me on how to properly manage conditional inputs with validation in React Hook Form while using Valibot? Any help would be appreciated.

2

Answers


  1. I use zod for validation in my nextjs project. I had similar issue on my project where selection of week of the day should be array of numbers when type is Subscription and null when type is oneTime. Here is my approach.

    import { z } from "zod";
    
    const schema = z
      .object({
        type: z.string().min(1),
        recurrence: z.array(z.number().or(z.string())).optional(),
      })
      .refine(
        (data) => {
          if (data.type === "subscription" && !data.recurrence) {
            return !!data.recurrence;
          }
          return true;
        },
        {
          path: ["recurrence"],
          message: "Please select at least one day.",
        }
      );
    
    export default schema;

    Here the data through form can be accessed in the refine method, and custom validation can be done. Maybe there are similar methods in valibot too(check method as of the documentation)

    For valibot this should work

    const CustomObjectSchema = v.pipe(
      v.object({
        type: v.string(),
        recurrence: v.optional(v.array(v.number())),
      }),
      v.check(
        (input) => input.type === "subscription" && input.recurrence.length === 0,
        'Select at least one day'
      )
    );
    Login or Signup to reply.
  2. If user pick supplier as "JS" the ecmaVersion field will get required
    My solution to the problem was supported by the maintainer

    import * as v from 'valibot';
    
    export const schema1 = v.object({
      name: v.pipe(
        v.string(),
        v.trim(),
        v.nonEmpty(),
      ),
    });
    
    /*
    
    // This won't work
    
    const schema2 = v.object({
      supplier: v.picklist(['JS', 'GO']),
      ecmaVersion: v.union(
        [v.null(), v.string()],
        [v.check((input) = input.supplier !== 'JS', 'ecmaVersion required'],
      ),
    });
    */
    
    export const schema2 = v.pipe(
      v.object({
        supplier: v.picklist(['JS', 'GO']),
        ecmaVersion: v.optional(v.string())
      }),
      v.forward(
        v.check((input) => input.supplier !== 'JS', 'ecmaVersion required'),
        ['ecmaVersion']
      )
    )
    
    // This won't work
    // const Schema = v.object({
    //   ...schema1.entries,
    //   ...schema2.entries,
    // });
    
    const Schema = v.intersect([
      schema1,
      schema2,
    ]);
    
    
    
    const result = v.safeParse(Schema, {
      name: 'Some name',
      supplier: 'JS',
      recurrence: undefined, // with JS is invalid
    });
    
    console.log(result);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search