react-hook-formzod

How to parse Zod to identify if field is required?


I am wondering if I could use Zod to determine when a field is required so I can pass this boolean to the input e.g. <input required={/* Use Zod to determine this value */} />. The main reason I asking is for styling purposes such as displaying * when the field is required.

const Component = () => {
  const schema = z.object({
    name: z.string(),
    address: z.string().optional(),
  });

  type FormValues = z.infer<typeof schema>;

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>({
    defaultValues: {
      name: '',
      address: undefined,
    },
    resolver: zodResolver(schema),
  });

  const onSubmit = handleSubmit((data) => console.log(data));

  return (
    <form onSubmit={onSubmit}>
      <input
        {...register('name', {
          required: /* Use Zod to determine this value */,
        })}
      />
      {errors?.name && <p>{errors.name.message}</p>}

      <input {...register('address'{
          required: /* Use Zod to determine this value */,
        })}
      />

      <input type="submit" />
    </form>
  );
};

Solution

  • One option is to just inspect if the schema is an instanceof z.ZodOptional. For example,

    const schema = z.number().optional();
    // ...
    
    <input required={!(schema instanceof z.ZodOptional)} />
    

    In your case, you're using z.object for your schema so you could instead look at the shape field like:

    <input required={!(schema.shape.name instanceof z.ZodOptional)} />
    

    This is taking advantage of the fact that .optional() will wrap the inner schema in a ZodOptional instance. If you have further refinements you may end up with a ZodEffect (or something else) that is internally optional. There doesn't seem to be first party support for reflecting on the type of the field without deeply handling all types, but you could at least derive it from the field in the schema if you know it will not be a ZodEffect.