skip to Main Content

I try to add yup validation to my form which is built with react-hook-form. I also use the standard components from @headlessui to build my components. My usecase is the following:
If the Radio Input is checked with "Yes" the Text Input should be required, otherwise the Text Input is optional.

enter image description here

For some reason I can’t add conditional validation to my radio button component. Maybe it has something todo with the Controller Component of react-hook-form.

I get the following error message:

  Overload 1 of 4, '(keys: string | string[], builder: ConditionBuilder<StringSchema<string | undefined, AnyObject, undefined, "">>): StringSchema<string | undefined, AnyObject, undefined, "">', gave the following error.
    Argument of type '{ is: string; then: yup.StringSchema<string, yup.AnyObject, undefined, "">; otherwise: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">; }' is not assignable to parameter of type 'ConditionBuilder<StringSchema<string | undefined, AnyObject, undefined, "">>'.
      Object literal may only specify known properties, and 'is' does not exist in type 'ConditionBuilder<StringSchema<string | undefined, AnyObject, undefined, "">>'.typescript(2769)

This is my TestForm component and here is also a codesandbox:
https://codesandbox.io/p/sandbox/nice-framework-vkx7k5?file=%2Fcomponents%2Fform%2FTest%2FTestForm.tsx%3A46%2C17

"use client";

import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { Controller, useForm } from "react-hook-form";
import InputField from "../../ui/InputField";
import RadioGroupInput from "../../ui/RadioGroupInput";
import { useFormState } from "./TestFormContext";

const validationSchema = yup.object({
  radioButtons: yup.string().required("Needed"),
  textInput: yup.string().when("radioButtons", {
    is: "Yes",
    then: yup.string().required("Needed"),
    otherwise: yup.string(),
  }),
});

export type FirstPageFormData = yup.InferType<typeof validationSchema>;

export default function TestForm() {
  const { setFormData, formData } = useFormState();

  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting, isLoading },
    control,
    getValues,
    watch,
  } = useForm<FirstPageFormData>({
    defaultValues: formData,
    resolver: yupResolver(validationSchema),
    shouldFocusError: false,
  });

  const watchAllFields = watch();

  async function onSubmit(data: FirstPageFormData) {
    setFormData((formData) => ({ ...formData, ...data }));
    alert(JSON.stringify(formData));
  }

  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div className="bg-white mt-6 px-4 py-5 shadow sm:rounded-lg sm:p-6">
          <div className="col-span-6">
            <Controller
              name="radioButtons"
              control={control}
              rules={{
                required: true,
              }}
              render={({ field }) => (
                <RadioGroupInput
                  label="Radio Buttons"
                  type="ghost"
                  error={errors.radioButtons}
                  radioButtons={[
                    {
                      title: "Yes",
                    },
                    {
                      title: "No",
                    },
                  ]}
                  field={field}
                />
              )}
            />
          </div>
          <div className="col-span-6 sm:col-span-3">
            <InputField
              id="textInput"
              name="textInput"
              type="text"
              label="Text Input"
              register={register("textInput")}
              error={errors.textInput}
            />
          </div>
        </div>
        <div className="mt-4 flex justify-end gap-4">
          <input
            type="submit"
            className="bg-gray-900 text-white p-2 rounded-md flex w-28 justify-center cursor-pointer hover:bg-gray-700"
            disabled={isLoading}
            value="Submit"
          />
        </div>
      </form>
      <div>{JSON.stringify(watchAllFields)}</div>
    </div>
  );
}

I tried to use yup with the following format

const validationSchema = yup.object({
  radioButtons: yup.string().required("Needed"),
  textInput: yup.string().when("radioButtons", {
    is: "Yes",
    then: yup.string().required("Needed"),
    otherwise: yup.string(),
  }),
});

and also in this format

const validationSchema = yup.object({
  radioButtons: yup.string().required("Needed"),
  textInput: yup.string().when("radioButtons", (val, schema) => {
    if (val === "Yes") return yup.string().required();
    else return yup.string().notRequired();
  }),
});

but I ended up with the error I mentioned.

2

Answers


  1. what version of yup are you using in your project?

    I had the same error with "yup": "^1.2.0"
    also in another project I am using an older version which is:
    "yup": "^0.32.11" and I used the same approach you used and worked fine without any issues.

    however, this should work without any errors:

    const validationSchema = yup.object().shape({
        radioButtons: yup.string().required("Needed"),
        textInput: yup
          .string()
          .when("radioButtons", ([radioButtons], schema) =>
            radioButtons === "yes" ? schema.required("Needed") : schema.nullable().notRequired()
          )
      });
    
    Login or Signup to reply.
  2. I updated the schema to this and it works. They might have updated how the .when stuff works

    const validationSchema = yup.object({
      radioButtons: yup.string().required("Needed"),
      textInput: yup.string().when('radioButtons', {
        is: 'Yes',
        then: (schema) => schema.required("Needed"),
        otherwise: (schema) => schema, // technically this otherwise isnt needed
      }),
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search