Date Picker
A date or date-range input with calendar popover, locale-aware formatting, clearable input, and animated transitions.
Basic
A production-ready date picker built by composing Popover + Calendar + Input. Supports single date and range selection, locale formatting, disabled dates, and animated popover transitions.
Installation
Install the component via the CLI in one command.
npx @work-rjkashyap/unified-ui add date-pickerpnpm dlx @work-rjkashyap/unified-ui add date-pickernpx @work-rjkashyap/unified-ui add date-pickerbunx @work-rjkashyap/unified-ui add date-pickerIf you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.
Or install the full package
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm install @work-rjkashyap/unified-uipnpm add @work-rjkashyap/unified-uiyarn add @work-rjkashyap/unified-uibun add @work-rjkashyap/unified-uiAnatomy
import { DatePicker } from "@work-rjkashyap/unified-ui";Basic Usage
Drop DatePicker anywhere you need a date input. It manages its own internal state by default (uncontrolled) and opens a calendar popover on click.
<DatePicker onSelect={(date) => console.log(date)} />Single Date Selection
The default mode selects a single date. The popover closes automatically after selection.
const [date, setDate] = useState<Date | null>(null);
<DatePicker
value={date}
onSelect={setDate}
placeholder="Select a date"
/>;Range Selection
Set mode="range" to allow selecting a start and end date. Click once for the start, then again for the end.
const [range, setRange] = useState<DateRange | null>(null);
<DatePicker
mode="range"
valueRange={range}
onSelectRange={setRange}
placeholder="Select date range"
/>;Sizes
| Size | Height | Use Case |
|---|---|---|
sm | 32px | Compact toolbars, sidebars |
md | 36px | Default — most contexts |
lg | 40px | Prominent forms, hero areas |
Disabled Dates
Use the disabledDate function to disable specific dates, or pass minDate / maxDate to restrict the selectable range.
// Disable past dates
<DatePicker
disabledDate={(date) => date < new Date()}
placeholder="Future dates only"
/>
// Restrict to a date range
<DatePicker
minDate={new Date(2025, 0, 1)}
maxDate={new Date(2025, 11, 31)}
placeholder="2025 only"
/>Clearable
By default, a clear button (×) appears when a date is selected. Set clearable={false} to disable it.
Locale Formatting
Dates are formatted using the browser's toLocaleDateString. Pass a locale string to control the output format.
<DatePicker locale="en-US" placeholder="MM/DD/YYYY" />
<DatePicker locale="en-GB" placeholder="DD/MM/YYYY" />
<DatePicker locale="de-DE" placeholder="TT.MM.JJJJ" />Default Month
Set the initially displayed month in the calendar without controlling it:
<DatePicker defaultMonth={new Date(2025, 11)} placeholder="December 2025" />Popover Alignment
Control where the calendar popover appears relative to the trigger:
<DatePicker align="start" placeholder="Align start (default)" />
<DatePicker align="center" placeholder="Align center" />
<DatePicker align="end" placeholder="Align end" />Disabled State
In a Form
A common pattern is wrapping DatePicker in a FormField for label, description, and error handling:
<FormField label="Start Date" description="When should the campaign begin?">
<DatePicker
value={startDate}
onSelect={setStartDate}
placeholder="Pick a date"
minDate={new Date()}
/>
</FormField>Controlled
Use value and onSelect for single mode, or valueRange and onSelectRange for range mode.
// Single
const [date, setDate] = useState<Date | null>(null);
<DatePicker
value={date}
onSelect={setDate}
placeholder="Pick a date"
/>;
// Range
const [range, setRange] = useState<DateRange | null>(null);
<DatePicker
mode="range"
valueRange={range}
onSelectRange={setRange}
placeholder="Select range"
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
mode | "single" | "range" | "single" | Selection mode — single date or date range. |
value | Date | null | — | The selected date (single mode, controlled). |
valueRange | DateRange | null | — | The selected range (range mode, controlled). |
onSelect | (date: Date | null) => void | — | Callback for single-date selection. |
onSelectRange | (range: DateRange | null) => void | — | Callback for range selection. |
placeholder | string | "Pick a date" | Placeholder text shown when no date is selected. |
size | "sm" | "md" | "lg" | "md" | Size of the trigger input. |
disabled | boolean | false | Whether the picker is disabled. |
clearable | boolean | true | Show a clear (×) button when a date is selected. |
locale | string | "en-US" | Locale string for date formatting. |
disabledDate | (date: Date) => boolean | — | Function returning true for dates that should be disabled. |
minDate | Date | — | Minimum selectable date. |
maxDate | Date | — | Maximum selectable date. |
defaultMonth | Date | — | Default month to display when no date is selected. |
align | "start" | "center" | "end" | "start" | Alignment of the popover relative to the trigger. |
className | string | — | Additional CSS classes on the trigger button. |
contentClassName | string | — | Additional CSS classes on the popover content. |
Motion
- Popover open/close — Uses the
scaleInpreset (scale + opacity) viaAnimatePresencefor smooth enter/exit transitions. - The calendar inside the popover uses its own month-transition animation (directional slide).
- All animations respect
prefers-reduced-motionviauseReducedMotion().
Keyboard Navigation
| Key | Action |
|---|---|
Enter / Space | Open the calendar popover (when trigger is focused). |
Escape | Close the popover. |
ArrowLeft | Move focus to the previous day (inside calendar). |
ArrowRight | Move focus to the next day (inside calendar). |
ArrowUp | Move focus up one week (inside calendar). |
ArrowDown | Move focus down one week (inside calendar). |
PageUp | Navigate to the previous month. |
PageDown | Navigate to the next month. |
Enter | Select the focused date. |
Accessibility
- The trigger renders a
<button>witharia-expandedandaria-haspopup="dialog". - The popover uses
role="dialog"semantics. - The clear button has
aria-label="Clear date"and is keyboard accessible. - The underlying
Calendarprovides full ARIA grid semantics,aria-labelon each day, andaria-selectedon selected dates. - Disabled state is forwarded to the trigger button.
- Focus is managed between trigger and calendar popover.
Design Tokens
| Token | Usage |
|---|---|
--input | Trigger border color |
--ring | Focus ring and open-state border/shadow |
--background | Trigger and popover background |
--border | Popover border |
--muted-foreground | Placeholder text, calendar icon color |
--primary | Selected date highlight (via Calendar) |
--radius-md | Trigger border radius |
--radius-lg | Popover border radius |
--duration-fast | Transition speed |
--shadow-lg | Popover shadow |