NimUI
ComponentsForms

DatePicker

A date input with a calendar popover, plus a range variant

DatePicker composes Popover, Calendar, and a button-styled trigger into a ready-to-use date input. Two variants ship: DatePicker for a single date and DateRangePicker for a start–end range with a two-month preview.

Import

import { DatePicker, DateRangePicker } from '@nim-ui/components';

Single Date

DatePicker supports both controlled (value + onChange) and uncontrolled (defaultValue) modes. The trigger shows the formatted date via date-fns.

Booking Date
Code
<DatePicker
  value={date}
  onChange={setDate}
  name="bookingDate"
  placeholder="Pick a booking date"
/>
import { useState } from 'react';
import { DatePicker } from '@nim-ui/components';

export function BookingForm() {
  const [date, setDate] = useState<Date | undefined>();

  return (
    <DatePicker
      value={date}
      onChange={setDate}
      placeholder="Pick a date"
    />
  );
}

Custom Format

Pass any date-fns format string to control how the selected date is displayed in the trigger.

Operational Format
Code
<DatePicker value={date} onChange={setDate} format="yyyy-MM-dd" />
<DatePicker value={date} onChange={setDate} format="yyyy-MM-dd" />
<DatePicker value={date} onChange={setDate} format="MMM d, yyyy" />
<DatePicker value={date} onChange={setDate} format="PPP" /> {/* default */}

Buddhist Era Display

Use calendar="buddhist" when the field should display Thai Buddhist Era years. The selected value is still a normal JavaScript Date, and hidden form inputs still serialize as Gregorian ISO date strings (YYYY-MM-DD).

Thai Buddhist Era
Code
<DatePicker
  value={date}
  onChange={setDate}
  calendar="buddhist"
  format="yyyy-MM-dd"
  name="serviceDate"
/>

// Visible: 2569-06-16
// Hidden input: 2026-06-16

Range Picker

DateRangePicker renders two months side by side and returns a DateRange ({ from, to }) object.

Stay Window
Code
<DateRangePicker
  value={range}
  onChange={setRange}
  fromName="checkIn"
  toName="checkOut"
/>
import { useState } from 'react';
import { DateRangePicker } from '@nim-ui/components';
import type { DateRange } from 'react-day-picker';

export function StayRange() {
  const [range, setRange] = useState<DateRange | undefined>();

  return (
    <DateRangePicker
      value={range}
      onChange={setRange}
      placeholder="Check-in — Check-out"
    />
  );
}

Form Integration

DatePicker renders a hidden <input type="hidden" name={name}> with a Gregorian ISO date value (YYYY-MM-DD) whenever name is provided. That avoids UTC timezone shifts for date-only fields and works with native form submissions and libraries like react-hook-form via Controller. Pass an id to wire it up with FormField:

import { FormField, DatePicker } from '@nim-ui/components';

<FormField label="Event date" name="event-date">
  <DatePicker id="event-date" name="eventDate" />
</FormField>

For ranges, pass fromName and toName to render two hidden ISO inputs:

<DateRangePicker
  value={range}
  onChange={setRange}
  fromName="dateFrom"
  toName="dateTo"
/>

Presets

Add operational presets for common report ranges:

Report Presets
Code
<DateRangePicker
  presets={[
    { label: 'Today', value: todayRange },
    { label: 'Last 7 days', value: last7Days },
    { label: 'This month', value: thisMonth },
  ]}
/>
<DateRangePicker
  presets={[
    { label: 'This week', value: { from: weekStart, to: weekEnd } },
    { label: 'Last 30 days', value: () => getLast30Days() },
  ]}
/>

Uncontrolled

Skip value / onChange and pass defaultValue to let the component manage its own state.

<DatePicker defaultValue={new Date()} />

Disabled

<DatePicker value={date} onChange={setDate} disabled />

Props

DatePicker

NameTypeDefaultDescription
valueDate-Controlled selected date
defaultValueDate-Uncontrolled initial date
onChange(date: Date | undefined) => void-Callback fired when the selected date changes
placeholderstring'Pick a date'Text shown in the trigger when no date is selected
format'short' | 'medium' | 'long' | 'full' | 'iso' | string'PPP'date-fns format string for the trigger label
calendar'gregory' | 'buddhist''gregory'Display years as Gregorian CE or Buddhist Era; values remain Date objects
localeLocale | string-Display locale. String locales use Intl; date-fns Locale objects also localize the calendar UI
formatDate(date: Date) => string-Custom display formatter for product-specific policies
disabledbooleanfalseDisable the trigger button
idstring-Input id for FormField / label association
namestring-Name attribute for native form submission (renders a hidden input with a YYYY-MM-DD ISO date value)
classNamestring-Additional CSS classes for the trigger button

DateRangePicker

NameTypeDefaultDescription
valueDateRange-Controlled selected range ({ from, to })
defaultValueDateRange-Uncontrolled initial range
onChange(range: DateRange | undefined) => void-Callback fired when the range changes
placeholderstring'Pick a date range'Text shown when no range is selected
format'short' | 'medium' | 'long' | 'full' | 'iso' | string'LLL dd, y'date-fns format string applied to both boundary dates
calendar'gregory' | 'buddhist''gregory'Display years as Gregorian CE or Buddhist Era; hidden values remain YYYY-MM-DD ISO date strings
localeLocale | string-Display locale. String locales use Intl; date-fns Locale objects also localize the calendar UI
formatDate(date: Date) => string-Custom display formatter for product-specific policies
disabledbooleanfalseDisable the trigger button
idstring-Input id for FormField / label association
fromNamestring-Name attribute for the hidden start-date input (YYYY-MM-DD)
toNamestring-Name attribute for the hidden end-date input (YYYY-MM-DD)
presetsDateRangePickerPreset[]-Preset buttons rendered beside the calendar
showPresetsbooleantrueShow preset buttons when presets are provided
classNamestring-Additional CSS classes for the trigger button

Accessibility

  • Trigger is a button — fully keyboard-focusable with the same focus ring as other nim-ui controls
  • Popover manages focus: opens to the calendar grid, returns focus to the trigger on close
  • Pass an id and wire it to a <label htmlFor> (or use FormField) to announce the field to screen readers
  • Calendar inherits the full keyboard support documented in Calendar
  • Hidden input (name prop) ensures the date is submitted natively without losing semantic meaning
  • Calendar — standalone calendar used inside the popover
  • Popover — the underlying floating layer
  • FormField — wrap DatePicker with label + help text + error state

On this page