Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use shadcn/ui Range Date Picker inside Form?

I have a problem with using The Range Date Picker inside the Form component. To be exact, I need an object to store the {from, to} values of the range, but using an object as a Form field value makes error messages not work. I just get undefined as an error message.

The current fix I'm using, is that I just modified the Form Message Component to render the errors a bit differently, but I think it's more of a hack than the proper way.

The code:

const formSchema = z.object({
  title: z.string().min(2, {
    message: "Title must be at least 2 characters.",
  }),
  date: z.object({
    from: z.date(),
    to: z.date(),
  }),
});

function NewEventPage() {
  const form = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: {
      title: "",
      date: {},
    },
  });

  function onError(a) {
    console.log(a);
    /*
    title:
      message: "Title must be at least 2 characters."
      ref: {focus: ƒ, select: ƒ, setCustomValidity: ƒ, reportValidity: ƒ}
      type: "too_small"
    date:
      from: {message: 'Required', type: 'invalid_type', ref: undefined}
      to: {message: 'Required', type: 'invalid_type', ref: undefined}
    */
  }

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit, onError)}
        className="mx-auto mt-12 grid max-w-screen-lg grid-cols-2 gap-x-12 gap-y-8"
      >
        <h1 className="col-span-2 scroll-m-20 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
          Create A New event
        </h1>

        <FormField
          control={form.control}
          name="title"
          render={({ field }) => {
            return (
              <FormItem>
                <FormLabel>Event Title</FormLabel>
                <FormControl>
                  <Input placeholder="The best title ever" {...field} />
                </FormControl>
                <FormDescription>Give a name for your event</FormDescription>
                <FormMessage />
              </FormItem>
            );
          }}
        />

        <FormField
      control={form.control}
      name="date"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Date</FormLabel>
          <FormControl>
            <Popover>
              <PopoverTrigger asChild>
                <Button
                  variant={"outline"}
                  className={cn(
                    "w-full justify-start text-left font-normal",
                    !field.value && "text-muted-foreground",
                  )}
                >
                  <CalendarIcon className="mr-2 h-4 w-4" />
                  {field.value?.from ? (
                    field.value.to ? (
                      <>
                        {format(field.value.from, "LLL dd, y")} -{" "}
                        {format(field.value.to, "LLL dd, y")}
                      </>
                    ) : (
                      format(field.value.from, "LLL dd, y")
                    )
                  ) : (
                    <span>Pick a date</span>
                  )}
                </Button>
              </PopoverTrigger>
              <PopoverContent className="w-auto p-0" align="start">
                <Calendar
                  initialFocus
                  mode="range"
                  defaultMonth={field.value?.from}
                  selected={field.value}
                  onSelect={field.onChange}
                  numberOfMonths={2}
                />
              </PopoverContent>
            </Popover>
          </FormControl>
          <FormDescription>
            Select the date for when the event will take place
          </FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />

        <Button type="submit" className="col-span-2">
          Submit
        </Button>
      </form>
    </Form>
  );
}

Title shows the error, but date shows undefined: Title shows the error, but date shows undefined

like image 523
Au Gus Tas Avatar asked Oct 17 '25 20:10

Au Gus Tas


2 Answers

I have got a solution for this issue, also I have resolved the solution for date picker not saving/maintaining the selected value.

I have updated the UI Selected value will never sets to initial date (major issues resolved with this picker). Stunning UI using shad cn select. Completely customized using shad-cn components You can find the solution at: https://nurture-tech-ebon.vercel.app/blog/how-to-add-year-selection-shadcn image

like image 122
zahoor Avatar answered Oct 19 '25 10:10

zahoor


I have found a solution:

  1. Define "from: and "to" as optional:

    z.object({ from: z.date().optional(), to: z.date().optional(), })

  2. Add "SuperRefine" validation:

    .superRefine((data, ctx) => { if (data.from === undefined || data.to === undefined) { return ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Please select a date range.', }) } return data })

  3. Then, since "from" is not optional in the DataRage type, we have to specify that the value that the input is going to receive is of type DateRage, this is just so that typescript does not detect a type error:

    <DatePickerRange defaultValue={field.value as DateRange} ... >

The validation would be like this:

const formSchema = z.object({
  date_range: z
    .object({
      from: z.date().optional(),
      to: z.date().optional(),
    })
    .superRefine((data, ctx) => {
      if (data.from === undefined || data.to === undefined) {
        return ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Please select a date range.',
        })
      }
      return data
    }),
})
like image 41
Omar Arturo Avatar answered Oct 19 '25 10:10

Omar Arturo