Date value from Next.js form with Shadcn-ui Date Picker returns null in action handler

0

I’m working on a Next.js project utilizing Shadcn-ui components, specifically Inputs and a Date Picker within a Form. The form submission is handled by a formaction that processes the submitted data. A live, simplified version of my issue can be explored HERE.

Issue: When selecting a date using the Date Picker, the selectedDate correctly logs to the console within the onSelect event in the Date Picker component (date-picker-form.tsx). However, when I try to access this date value in my action handler (actions.ts), it’s logged as null. I’m trying to understand why the date value isn’t being passed through correctly.

actions.ts

'use server';

import { redirect } from 'next/navigation';

export async function createDbEntry(formData: FormData) {
  const data = {
    text_input: formData.get('text_input') as string,
    datepicker: formData.get('datepicker') as string,
  };

  console.log(data);  // Here, `datepicker` is logged as `null`

  redirect('/');
}

date-picker-form.tsx

'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { CalendarIcon } from '@radix-ui/react-icons';
import { format } from 'date-fns';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form';
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover';
import { Input } from '@/components/ui/input';
import { createDbEntry } from '@/lib/actions';

const FormSchema = z.object({
  text_input: z.string(),
  datepicker: z.date({
    required_error: 'A date of birth is required.',
  }),
});

export function DatePickerForm() {
  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
  });

  return (
    <Form {...form}>
      <form className="space-y-8">
        {/* Input Field */}
        <FormField
          control={form.control}
          name="text_input"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Text Input</FormLabel>
              <FormControl>
                <Input {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        {/* Datepicker Field */}
        <FormField
          control={form.control}
          name="datepicker"
          render={({ field }) => (
            <FormItem className="flex flex-col">
              <FormLabel>Date Picker</FormLabel>
              <Popover>
                <PopoverTrigger asChild>
                  <FormControl>
                    <Button
                      variant={'outline'}
                      className={cn(
                        'w-[240px] pl-3 text-left font-normal',
                        !field.value && 'text-muted-foreground'
                      )}
                    >
                      {field.value ? (
                        format(field.value, 'PPP')
                      ) : (
                        <span>Pick a date</span>
                      )}
                      <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
                    </Button>
                  </FormControl>
                </PopoverTrigger>
                <PopoverContent className="w-auto p-0" align="start">
                  <Calendar
                    mode="single"
                    selected={field.value}
                    onSelect={(selectedDate) => {
                      console.log('selectedDate', selectedDate); // Here date logs fine
                      field.onChange(selectedDate);
                    }}
                    disabled={(date) =>
                      date > new Date() || date < new Date('1900-01-01')
                    }
                    initialFocus
                  />
                </PopoverContent>
              </Popover>
              <FormDescription>
                Your date of birth is used to calculate your age.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button formAction={createDbEntry}>Submit</Button>
      </form>
    </Form>
  );
}

Attempts to Resolve:

  • Verified that other form data, like text inputs, are captured correctly.
  • Ensured field.onChange is called with the correct date within onSelect.

Could anyone help me identify why the date value is null when accessed in the action handler? Is there a step I’m missing to ensure the date value is correctly passed through the form submission process?