vaiperui

components / date-range-picker

DateRangePicker

Field that opens a Calendar to choose a start and an end, with shortcut presets.

How to use

Shows `start – end` and opens a `Calendar` in range mode; the panel closes after the second click. `onValueChange` runs twice per range: first with only `from`, then with `from` and `to`. `presets` adds a column of shortcuts (Today, Last 7 days...) that set the whole range; pass `true` for the defaults or your own list, starting from `getDatePresets()`.

preview
DateRangePicker.tsx
import { DateRangePicker, getDatePresets } from "vaiperui";
const [period, setPeriod] = useState<DateRange>({});
<DateRangePicker label="Stay" presets value={period} onValueChange={setPeriod} />
// Custom list, translated labels
<DateRangePicker presets={[
...getDatePresets({ today: "Today" }).slice(0, 3),
{ label: "Q4", range: { from: new Date(2026, 9, 1), to: new Date(2026, 11, 31) } },
]} />

Presets

`presets` adds a shortcut column. `true` uses the defaults; pass a list for your own.

preview
presets
no presets
presets.tsx
<DateRangePicker presets />
<DateRangePicker presets={[{ label: "Q4", range: { from, to } }]} />

Sizes

preview
sm
md
lg
sizes.tsx
<DateRangePicker size="sm" />
<DateRangePicker size="md" />
<DateRangePicker size="lg" />

States

preview
Extra detail
helper
This is required
error
disabled
read only
states.tsx
<DateRangePicker label="..." helperText="..." />
<DateRangePicker label="..." errorMessage="..." />
<DateRangePicker label="..." disabled />
<DateRangePicker label="..." readOnly />

Props

PropValuesDefaultDescription
value / defaultValue{ from?: Date; to?: Date }noneRange, controlled or initial. Without `to`, only the start was chosen
onValueChange(range: DateRange) => voidnoneCalled on every click
presetsboolean | { label: string; range: { from: Date; to: Date } }[]noneShortcut column; true uses getDatePresets(). Presets outside minDate/maxDate are disabled
presetLabels{ today, last7Days, last30Days, thisMonth, lastMonth }noneTranslates the default presets (presets={true})
fromName / toNamestringnoneForm field names for start and end; each sends yyyy-mm-dd
label / helperTextstringnoneLabel above the field and help text below
errorMessagestringnoneError text; its presence alone forces the error state
placeholderstringfrom the localeText when nothing is chosen (e.g. mm/dd/yyyy)
disabled / readOnlybooleanfalseDoes not open the panel; readOnly still shows the value
variantring | outlineringFocus style, same as Input
size / radiussm | md | lg / none | sm | md | lg | fullmd / mdField height and corner rounding
aria-labelstringnoneAccessible name when there is no label
panelLabelstringnoneAccessible name of the open panel
minDate / maxDateDatenoneFirst and last allowed day; the rest and the month arrows leading outside are disabled
localestring"en-US"Language of month/day names and the date format (BCP 47)
weekStartsOn0 – 60First weekday (0 = Sunday)
previousMonthLabel / nextMonthLabelstring"Previous month" / "Next month"Accessible names of the month buttons
variantColor / customColor / animationprimary | success | warning | danger / CSS color / none | smooth | fast | bounceprimary / smoothColor of the selection and focus, and transition speed

Accessibility

  • The trigger is a `<button>` with `aria-haspopup="dialog"` and `aria-expanded` reflecting the panel state.
  • `label` is linked with `htmlFor`; without `label`, the trigger uses `aria-label`.
  • `errorMessage` sets `aria-invalid` and `aria-describedby` to the message; otherwise `helperText` is linked through `aria-describedby`.
  • The panel is a `role="dialog"` named by `panelLabel`, rendered in a portal on `document.body`.
  • `disabled` disables the button; `readOnly` keeps it focusable but the panel never opens.
  • The trigger text reads as `start – end`; while only the start is chosen it shows `start – …`.
  • Presets are `<button>`s with `aria-pressed` when they match the current range, and `disabled` when they fall outside `minDate`/`maxDate`.
  • Opening the panel focuses a day in the range `Calendar`, which follows its grid pattern.

Keyboard

KeyAction
Enter / SpaceOpens or closes the panel from the trigger.
Arrow keys, Home, End, Page Up/DownNavigate the days inside the open panel (see Calendar); Enter or Space picks the start, then the end, which closes the panel.
EscCloses the panel and returns focus to the trigger.

Keep in mind

  • The panel does not trap focus: Tab leaves it, and because it is rendered at the end of `<body>`, Tab from the trigger does not enter it on its own.
  • Clicking outside closes the panel without moving focus back; only Esc restores focus to the trigger.
  • Pass `presetLabels` (or your own `presets`) translated when using presets; the defaults are in English. The dates cannot be typed.