Unified UI

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-picker
pnpm dlx @work-rjkashyap/unified-ui add date-picker
npx @work-rjkashyap/unified-ui add date-picker
bunx @work-rjkashyap/unified-ui add date-picker

If 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-ui
pnpm add @work-rjkashyap/unified-ui
yarn add @work-rjkashyap/unified-ui
bun add @work-rjkashyap/unified-ui

Anatomy

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

SizeHeightUse Case
sm32pxCompact toolbars, sidebars
md36pxDefault — most contexts
lg40pxProminent 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

PropTypeDefaultDescription
mode"single" | "range""single"Selection mode — single date or date range.
valueDate | nullThe selected date (single mode, controlled).
valueRangeDateRange | nullThe selected range (range mode, controlled).
onSelect(date: Date | null) => voidCallback for single-date selection.
onSelectRange(range: DateRange | null) => voidCallback for range selection.
placeholderstring"Pick a date"Placeholder text shown when no date is selected.
size"sm" | "md" | "lg""md"Size of the trigger input.
disabledbooleanfalseWhether the picker is disabled.
clearablebooleantrueShow a clear (×) button when a date is selected.
localestring"en-US"Locale string for date formatting.
disabledDate(date: Date) => booleanFunction returning true for dates that should be disabled.
minDateDateMinimum selectable date.
maxDateDateMaximum selectable date.
defaultMonthDateDefault month to display when no date is selected.
align"start" | "center" | "end""start"Alignment of the popover relative to the trigger.
classNamestringAdditional CSS classes on the trigger button.
contentClassNamestringAdditional CSS classes on the popover content.

Motion

  • Popover open/close — Uses the scaleIn preset (scale + opacity) via AnimatePresence for smooth enter/exit transitions.
  • The calendar inside the popover uses its own month-transition animation (directional slide).
  • All animations respect prefers-reduced-motion via useReducedMotion().

Keyboard Navigation

KeyAction
Enter / SpaceOpen the calendar popover (when trigger is focused).
EscapeClose the popover.
ArrowLeftMove focus to the previous day (inside calendar).
ArrowRightMove focus to the next day (inside calendar).
ArrowUpMove focus up one week (inside calendar).
ArrowDownMove focus down one week (inside calendar).
PageUpNavigate to the previous month.
PageDownNavigate to the next month.
EnterSelect the focused date.

Accessibility

  • The trigger renders a <button> with aria-expanded and aria-haspopup="dialog".
  • The popover uses role="dialog" semantics.
  • The clear button has aria-label="Clear date" and is keyboard accessible.
  • The underlying Calendar provides full ARIA grid semantics, aria-label on each day, and aria-selected on selected dates.
  • Disabled state is forwarded to the trigger button.
  • Focus is managed between trigger and calendar popover.

Design Tokens

TokenUsage
--inputTrigger border color
--ringFocus ring and open-state border/shadow
--backgroundTrigger and popover background
--borderPopover border
--muted-foregroundPlaceholder text, calendar icon color
--primarySelected date highlight (via Calendar)
--radius-mdTrigger border radius
--radius-lgPopover border radius
--duration-fastTransition speed
--shadow-lgPopover shadow

On this page