Search code examples
reactjstypescriptreact-hook-formzod

How to give default value (but not zero) in number type in zod and react-hooks-form?


I'm using zod and react-hooks-form for my form. I have input field for price. To prevent uncontrolled input error we need to give defaultValues, but it forces me to give 0 for price default value. I don't want it to be zero. Can I make it an empty somehow?

import * as z from "zod";

export const ProductSchema = z.object({
  title: z.string().min(2),
  price: z.number().positive(),
  discount: z.number().int().min(0).max(100),
  ...
})

export type ProductType = z.infer<typeof ProductSchema>;

my form looks like this:

const form = useForm<ProductType>({
    resolver: zodResolver(ProductSchema),
    defaultValues: {
      title: "",
      price: 0,
      discount: 0,
      ....
    },
  });

for styling I used shadcn form components:

<FormField
                  control={control}
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Price</FormLabel>
                      <Input
                        {...field}
                        disabled={isPending}
                        placeholder="Price of product"
                        type="number"
                        className="shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm border-gray-300 rounded-md bg-white"
                      />
                      <FormMessage>{errors.price?.message}</FormMessage>
                    </FormItem>
                  )}
                  name="price"
                />


Solution

  • in your zod schema

    price: z
        .string()
        .min(1, 'cannot be empty')
        .default('')
        .refine(     
          (val) => !isNaN(Number(val)),
          { message: 'Invalid price' }
        )
    

    here, it will only accept empty strings and numbers.

    now you can set default value as

     defaultValues: {
          title: "",
          price: "",
          discount: 0,
          ....
        },