Date Picker

A date picker component built with the Calendar and Dropdown components.

Dependencies

Source Code

"use client";
 
import { Calendar as CalendarIcon, CaretUpDown } from "@phosphor-icons/react";
import { VariantProps } from "cva";
 
import { cn } from "@/lib/utils";
import {
  Calendar,
  type CalendarProps,
} from "@/components/calendar";
import {
  Dropdown,
  DropdownItems,
  DropdownTrigger,
  useDropdownContext,
} from "@/components/dropdown";
import { inputStyle } from "@/components/input";
 
const DatePicker = ({
  children,
  ...props
}: React.ComponentProps<typeof Dropdown>) => {
  return <Dropdown {...props}>{children}</Dropdown>;
};
 
interface DatePickerTriggerProps
  extends React.ComponentProps<typeof DropdownTrigger> {
  className?: string;
  children: React.ReactNode;
  variant?: VariantProps<typeof inputStyle>["variant"];
  placeholder?: string;
}
 
const DatePickerTrigger = ({
  children,
  className,
  variant,
  placeholder,
  ...props
}: DatePickerTriggerProps) => {
  return (
    <DropdownTrigger asChild {...props}>
      <button
        type="button"
        className={cn(
          inputStyle({ variant }),
          "flex items-center gap-1.5 enabled:cursor-pointer",
          "relative w-full pr-10 pl-4",
          className
        )}
      >
        <CalendarIcon className="text-foreground-secondary shrink-0" />
        {children ?? (
          <span className="text-foreground-secondary">{placeholder}</span>
        )}
        <CaretUpDown
          weight="bold"
          className="text-foreground/80 absolute top-1/2 right-3 -translate-y-1/2 text-base"
        />
      </button>
    </DropdownTrigger>
  );
};
 
interface DatePickerContentCommonProps
  extends Omit<CalendarProps, "mode" | "value" | "onDateChange"> {
  className?: string;
  children?: React.ReactNode;
}
 
interface DatePickerContentSingleProps extends DatePickerContentCommonProps {
  mode?: "single";
  value: Date | null;
  onDateChange: (date: Date) => void;
}
 
interface DatePickerContentRangeProps extends DatePickerContentCommonProps {
  mode: "range";
  value: [Date, Date] | null;
  onDateChange: (dates: [Date, Date]) => void;
}
 
type DatePickerContentProps =
  | DatePickerContentSingleProps
  | DatePickerContentRangeProps;
 
const DatePickerPanel = ({
  className,
  children,
  mode,
  value,
  onDateChange,
  ...props
}: DatePickerContentProps) => {
  const { setOpen } = useDropdownContext();
 
  return (
    <DropdownItems className={cn(className)}>
      <Calendar
        {...props}
        mode={mode}
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        value={value as any}
        onDateChange={(date: Date | [Date, Date]) => {
          setOpen(false);
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          onDateChange(date as any);
        }}
      />
      {children}
    </DropdownItems>
  );
};
 
export { DatePicker, DatePickerTrigger, DatePickerPanel };

Features

  • Flexible Input: Supports different input variants and placeholders
  • Shortcuts: Predefined date shortcuts for quick selection
  • Smart Positioning: Automatically adjusts panel position
  • Keyboard Navigation: Full keyboard support inherited from Calendar

Anatomy

<DatePicker>
  <DatePickerTrigger />
  <DatePickerPanel />
</DatePicker>

API Reference

DatePicker

Extends the Dropdown component.

DatePickerTrigger

Extends the DropdownTrigger component.

PropDefaultTypeDescription

placeholder

-

string

The placeholder text to display when the date picker is empty.

variant

-

InputProps["variant"]

Check Input for more information.

DatePickerPanel

Extends the Calendar component.

Examples

Simple Date Picker

Basic usage for selecting a date.

Date Picker with Time

Adding time selection capability to the date picker.

Shortcuts

Using predefined shortcuts for quick date selection.

Best Practices

  1. Input Format:

    • Use clear date format patterns
    • Consider adding format hints in placeholder
    • Handle invalid date inputs gracefully
  2. Shortcuts:

    • Keep shortcuts relevant to use case
    • Use clear, descriptive labels
    • Consider common date ranges
  3. Mobile Considerations:

    • Test touch interactions
    • Consider using native pickers on mobile
    • Ensure sufficient touch targets