Date Picker
A sealed <DatePicker /> composed internally from Popover + Button + Calendar. Prefer this over <Input type="date" /> for consistent theming, keyboard nav, and a11y.
Basic Date Picker
Date Range Picker
Select a range of dates for filtering or scheduling.
With Presets
Add quick selection presets for common date ranges.
Usage
import { DatePicker, DateRangePicker } from "@gradeui/ui"
const [date, setDate] = React.useState<Date>()
const [range, setRange] = React.useState<DateRange>()
<DatePicker value={date} onChange={setDate} />
<DateRangePicker
value={range}
onChange={setRange}
numberOfMonths={2}
/>Compose your own
Need a different trigger, custom positioning, or a non-standard layout? Drop the sealed DatePicker and reach for the primitives directly — Calendar and Popover are exported from the same barrel.
import { Calendar, Popover, PopoverTrigger, PopoverContent, Button } from "@gradeui/ui"
import { format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : "Pick a date"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar mode="single" selected={date} onSelect={setDate} initialFocus />
</PopoverContent>
</Popover>Sidecar
The Markdown sidecar Studio (and the Grade MCP server, when it ships) reads to understand this component — frontmatter, when- to-use guidance, and canonical examples. Authored once at packages/ui/components/ui/date-picker.md and shipped inside the published @gradeui/ui tarball.
---
name: DatePicker
import: "@gradeui/ui"
props:
- value?: Date (single) | DateRange (range)
- onChange?: (value) => void — called on select or clear
- placeholder?: string — trigger label when empty (default "Pick a date" / "Pick a date range")
- disabled?: boolean
- format?: string — date-fns format token for the trigger label (default "PPP" single, "LLL dd, y" range)
- align?: "start" | "center" | "end" — popover align (default "start")
- side?: "top" | "right" | "bottom" | "left" — popover side
- captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years"
- className?: string — on the trigger button
- contentClassName?: string — on the PopoverContent
- icon?: ReactNode — replaces the default CalendarIcon
- numberOfMonths?: number — DateRangePicker only, default 2
when_to_use: Any date or date-range entry. Use DatePicker for a single date (DOB, due date, booking). Use DateRangePicker for a span (report period, stay dates, filter window). Prefer these over <Input type="date"> — consistent theming, keyboard nav, a11y, and no browser-native UI drift.
composes_with: [Label, Form, Card (in CardContent), Button (form submit)]
subcomponents: [DateRangePicker]
aliases: [datepicker, calendar input, date field, date range, datepickerios, react native date picker, calendar input field, date field control]
---
```jsx
// Single date
<div className="grid gap-1.5">
<Label htmlFor="dob">Date of birth</Label>
<DatePicker
value={date}
onChange={setDate}
placeholder="Select your birthday"
/>
</div>
```
```jsx
// Date range
<DateRangePicker
value={range}
onChange={setRange}
numberOfMonths={2}
/>
```
```jsx
// With presets — pair with Button shortcuts
<div className="flex items-center gap-2">
<DatePicker value={date} onChange={setDate} />
<Button variant="outline" size="sm" onClick={() => setDate(new Date())}>Today</Button>
</div>
```
Built internally from Popover + Button + Calendar. If you need a custom trigger or different popover positioning, compose the primitives directly — Calendar and Popover are exported from the same barrel.