Search code examples
reactjsreact-hook-form

How to convert values from input radio in boolean in React Hook Form?


I have input radio in React Hook Form and I try to use it as real boolean, instead of string.

I know that RHF have valueAsNumber to convert it as number. I thought that setValueAs was a generic way to allow any conversion but I can't make it work.

Code Sanbox


const schema = z.object({
  name: z.string().min(4, { message: "4 caractères minimum pour le name" }),
  developer: z.boolean() // A real boolean is expected here
});

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors }
  } = useForm({
    resolver: zodResolver(schema),
    defaultValues: {
      name: "John",
      developer: false // default as boolean
    }
  });

  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <input type="text" placeholder="Name" {...register("name")} />

      <p>
        Is developer ?&nbsp;
        <label>
          Oui
          <input
            {...register("developer", {
              setValueAs: (val) => true // Try to make it as a real boolean but doesn't work
            })}
            type="radio"
            value={true}
          />
        </label>
        <label>
          Non
          <input
            {...register("developer", {
              setValueAs: (val) => false
            })}
            type="radio"
            value={false}
          />
        </label>
      </p>

      <input type="submit" />

    </form>
  );
}

Any idea?


Solution

  • I find out how to get a boolean from a radio input in RHF.

    The solution with setValueAs, as I tried before, only works for text input (like type="text" or type="number"). For radio button, even if the value is a string, it doesn't work.

    So it can be solved by using a Controller component.

    Code sandbox

    function MyBooleanInput({ control, name }) {
      return (
        <Controller
          control={control}
          name={name}
          render={({ field: { onChange, onBlur, value, ref } }) => (
            <>
              <label>
                Oui
                <input
                  type="radio"
                  onBlur={onBlur} // notify when input is touched
                  onChange={() => onChange(true)} // send value to hook form
                  checked={value === true}
                  inputRef={ref}
                />
              </label>
              <label>
                Non
                <input
                  type="radio"
                  onBlur={onBlur} // notify when input is touched
                  onChange={() => onChange(false)} // send value to hook form
                  checked={value === false}
                  inputRef={ref}
                />
              </label>
            </>
          )}
        />
      );
    }
    

    This way, values are real booleans and zod doesn't throw an error.