DatePicker
A date picker component with range and presets.
Demo
Dependencies
lucide-reactclsxtailwind-merge
Props
This is a base primitive. It accepts standard HTML attributes plus className for styling via cn().
Source
"use client";
import { useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
import { CalendarIcon } from "lucide-react";
import { Calendar } from "./calendar";
export interface DatePickerProps {
value?: Date;
onChange?: (date: Date) => void;
placeholder?: string;
className?: string;
}
function formatDate(date: Date): string {
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
}
export function DatePicker({
value,
onChange,
placeholder = "Pick a date",
className,
}: DatePickerProps) {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const h = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node))
setOpen(false);
};
document.addEventListener("mousedown", h);
return () => document.removeEventListener("mousedown", h);
}, []);
return (
<div ref={ref} className={cn("relative", className)}>
<button
type="button"
onClick={() => setOpen(!open)}
className="flex w-full items-center gap-2 rounded-md border border-gray-200 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-gray-400"
>
<CalendarIcon className="h-4 w-4 text-gray-400" />
<span className={value ? "text-gray-900" : "text-gray-400"}>
{value ? formatDate(value) : placeholder}
</span>
</button>
{open && (
<div className="absolute left-0 top-full z-50 mt-1">
<Calendar
value={value}
onChange={(d) => {
onChange?.(d);
setOpen(false);
}}
/>
</div>
)}
</div>
);
}
CLI
npx genui add date-picker