Pick a from–to range for report filters, leave requests, bookings and campaign flights. Presets column, two months side by side (one on phones), a hover preview of the band, min / max length, and an Apply mode for expensive queries. Values are YYYY-MM-DD strings.
2026-11-01 → 2026-11-10 (10 days)
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { DateRangePicker, type IsoDateRange } from "@vamos-ui/react";
const [range, setRange] = React.useState<IsoDateRange | null>(null);
<DateRangePicker aria-label="Report period" presets value={range} onValueChange={setRange} />Presets are a listbox (↑ ↓ Home End, Enter). The grid uses the WAI-ARIA grid keyboard model. The selected range is announced: “From November 1, 2026 to November 10, 2026, 10 days”.
On glass, the range band is an opaque mix of the accent and the surface, so it never shows the page through it.
Examples
Apply to commit
commit="apply" holds the draft until Apply, so a dashboard runs one query per decision. Cancel or Esc discards it.
Revenue by channel
- Gross revenue
- $84,210
- Report queries run
- 1
Length limits & booked days
After the first click, days that would make the range shorter than minDays or longer than maxDays are disabled. excludeDisabled restarts a range that would span a booked day.
2 to 14 nights. Greyed-out dates are already booked.
Custom presets
Any { id, label, range(today) } list — here fiscal quarters. The active preset is highlighted in the listbox.
Typeable fields
trigger="input": two fields with the same parser as Date Picker; an end before the start is swapped.
Type both dates or pick them from the calendar.
Sizes & states
Small, disabled, a Field error and empty.
The period overlaps an issued invoice.
API
DateRangePicker
| Prop | Type | Default |
|---|---|---|
value / defaultValue{ from, to? } as YYYY-MM-DD. to is missing while the end is being picked. | IsoDateRange | null | — |
onValueChangeEvery change (immediate) or on Apply. | (value: IsoDateRange | null) => void | — |
presetstrue = Today, Yesterday, Last 7 / 30 / 90 days, This week, This / Last month, This year. Week presets follow the locale's week start. | boolean | DateRangePreset[] | false |
numberOfMonthsDrops to 1 below the sm breakpoint. | 1 | 2 | 2 |
commitImmediate closes after the end is picked; apply waits for the button. | "immediate" | "apply" | "immediate" |
minDays / maxDaysInclusive length limits in days. | number | — |
min / maxEarliest / latest date (YYYY-MM-DD). | string | — |
disabledDaysMatchers or YYYY-MM-DD strings. | DayMatcher | DayMatcher[] | — |
excludeDisabledA range may not span a disabled day. | boolean | false |
triggerOne trigger showing the range, or two typeable fields. | "button" | "input" | "button" |
nameFrom / nameToHidden inputs submitting YYYY-MM-DD. | string | — |
placeholderEmpty trigger text. | string | "Pick a date range" |
clearableClear in the footer (and in the input trigger). | boolean | false |
size / invalid / disabled / readOnly / requiredAs every control; also read from Field. | | — |
open / defaultOpen / onOpenChangePopover state. | boolean / (open) => void | — |
calendarPropsExtra grid props (showWeekNumber, renderDayExtra…). | DatePickerCalendarProps | — |
labelsdateRangePicker namespace: preset names, Apply / Cancel, days plural, summary announcement. | Partial<DateRangePickerLabels> | — |
DateRangePreset
| Prop | Type | Default |
|---|---|---|
idStable key. | string | — |
labelShown in the presets listbox. | string | — |
rangeComputed when the popover renders, from today in the provider's time zone. | (today: string, ctx: { weekStartsOn }) => { from: string; to: string } | — |