UnflowUI
Components

DatePicker

A date and date-range input with a dropdown calendar, optional shortcuts panel, and full i18n support.

Overview

DatePicker is a controlled input that opens a calendar dropdown for selecting a single date or a date range. Key features:

  • Single or range selection — controlled by isRange. Range mode uses a { from, to } value object.
  • Single or dual calendarmode="single" shows one month at a time; mode="dual" shows two months side-by-side for easier range picking.
  • Shortcuts — pass a shortcuts array for quick-select options (e.g. "Today", "This week").
  • Localization — driven by a BCP-47 locale code; any label can be overridden via localeText.
  • Form-compatible eventsonChange and onBlur mimic the React input event shape (e.target.name, e.target.value, e.target.type = 'date').

Import

import { DatePicker } from '@unflow.io/ui/components/DatePicker';

Props

PropTypeDefaultDescription
namestringRequired. Input name used in change/blur events
valueDatePickerValueControlled value — Date | null for single; { from, to } for range
isRangebooleanEnables range selection mode
mode'single' | 'dual'Number of calendar months shown in the dropdown
labelstringVisible label above the input
hintstringHelper text below the label
autoApplybooleanClose and apply on date click without an explicit Apply button
shortcutsDatePickerShortcutItem[]Quick-select date/range options
hideDaysOutsideMonthbooleanHide days from adjacent months in the calendar grid
minYearnumber1970Earliest selectable year in the year dropdown
maxYearnumbercurrent + 10Latest selectable year in the year dropdown
localestringactive i18n languageBCP-47 code controlling month names, weekday labels, format, and week start
weekStartsOn0–6locale defaultFirst day of the week (0 = Sunday, 1 = Monday, …, 6 = Saturday)
localeTextDatePickerLocaleTextInline string overrides — highest precedence over i18n and Intl API
onChange(e: DatePickerChangeEvent) => voidFires when the selected value changes
onBlur(e: DatePickerBlurEvent) => voidFires when the input loses focus
onCancel() => voidFires when the user cancels the dropdown
disabledbooleanDisables the input
requiredbooleanMarks the input as required

Value types

The value and onChange event type depend on whether isRange is set:

ModeValue shapeExample
Single (isRange={false})Date | null | undefinednew Date('2024-06-15')
Range (isRange={true}){ from: Date | null, to: Date | null } | null{ from: new Date(...), to: new Date(...) }

Important: Always pass Date objects. Strings and timestamps (numbers) are rejected at runtime.

Single date

'use client';
import { useState } from 'react';
import { DatePicker } from '@unflow.io/ui/components/DatePicker';

export function Example() {
  const [value, setValue] = useState<Date | null>(null);

  return (
    <DatePicker
      name="date"
      label="Select a date"
      isRange={false}
      mode="single"
      value={value}
      onChange={(e) => setValue(e.target.value as Date | null)}
    />
  );
}

Date range

'use client';
import { useState } from 'react';
import { DatePicker } from '@unflow.io/ui/components/DatePicker';

type RangeValue = { from: Date | null; to: Date | null } | null;

export function Example() {
  const [value, setValue] = useState<RangeValue>(null);

  return (
    <DatePicker
      name="dateRange"
      label="Select a date range"
      isRange
      mode="dual"
      value={value}
      onChange={(e) => setValue(e.target.value as RangeValue)}
    />
  );
}

Range selection works in two steps: the first click sets from; the second click sets to. Clicking a date before the current from resets from and starts the selection over.

With shortcuts

const now = new Date();
const shortcuts = [
  { label: 'Today', value: { from: startOfDay(now), to: endOfDay(now) } },
  {
    label: 'This week',
    value: {
      from: startOfDay(new Date(now.getFullYear(), now.getMonth(), now.getDate() - now.getDay())),
      to: endOfDay(new Date(now.getFullYear(), now.getMonth(), now.getDate() - now.getDay() + 6)),
    },
  },
];

<DatePicker
  name="dateRange"
  label="Select a period"
  isRange
  mode="dual"
  value={value}
  shortcuts={shortcuts}
  onChange={(e) => setValue(e.target.value as RangeValue)}
/>

Each shortcut value must match the picker's mode: a plain Date when isRange={false}, or a { from, to } object when isRange={true}.

Localization

<DatePicker
  name="date"
  label="Selecionar data"
  isRange={false}
  mode="single"
  locale="pt"
  weekStartsOn={1}
  localeText={{ apply: 'Aplicar', cancel: 'Cancelar', reset: 'Limpar' }}
  value={value}
  onChange={(e) => setValue(e.target.value as Date | null)}
/>

Locale resolution priority (highest → lowest):

  1. localeText prop — inline overrides for any label
  2. i18n translations — registered translations for the resolved locale
  3. Intl API fallback — automatic month/weekday names for unregistered locales

weekStartsOn accepts 0 (Sunday) through 6 (Saturday) and overrides the locale's CLDR default.

All overridable labels via localeText:

KeyDescription
months12-element array of month names (index 0 = January)
weekdays7-element array of short weekday labels (index 0 = Sunday)
today"Today" label
dateSingle-date input label
startDateRange "from" field label
endDateRange "to" field label
applyApply button label
cancelCancel button label
resetReset button label
previousMonthPrevious month button aria-label
nextMonthNext month button aria-label
shortcutsShortcuts panel heading
toggleOnCalendar open button aria-label
toggleOffCalendar close button aria-label
formatDate format string, e.g. 'MM/dd/yyyy'

Events

Both onChange and onBlur receive a synthetic event that mirrors the React input event shape:

type DatePickerChangeEvent = {
  type: 'change';
  target: { name: string; value: DatePickerValue; type: 'date' };
  currentTarget: { name: string; value: DatePickerValue };
  nativeEvent?: Event;
  preventDefault: () => void;
  stopPropagation: () => void;
  persist: () => void;
};

This makes DatePicker compatible with form libraries like React Hook Form that read e.target.name and e.target.value.

Customization (slotProps)

SlotPropsDescription
calendarIconReactNode (slot)Icon inside the calendar toggle button
separatorReactNode (slot)Element between the from/to inputs in range mode
calendarTogglerOmit<IIconButton, 'onClick' | 'aria-label' | 'type' | 'icon'>Calendar toggle button props
inputContainerBaseHTMLProps<HTMLDivElement>Outer wrapper element
inputLabelOmit<IInputLabel, ...>Label/hint component props
datePickerDropdownOmit<IDatePickerDropdown, ...>Advanced dropdown customization

Accessibility

  • The calendar toggle button uses localeText.toggleOn / localeText.toggleOff as its aria-label — always provide translated values when customizing locale.
  • Inside the calendar grid, arrow keys move focus between days; Enter and Space select the focused day.
  • The month/year selectors are keyboard-accessible dropdowns.
  • Provide an accessible label or aria-label on the component so screen readers can identify the input field.