Skip to content

Components · Search and discovery

DateRangePicker

Start and end dates: typed or picked on a one- or two-month calendar with a live preview, presets and length limits.

@rookcom/monarch-react/schedulingComponent

Report period with presets

2026-10-06 to 2026-11-04; at most 366 days.

Usage examples

Leave with a minimum length

Compact filter

Purpose

Picks a period such as a report range, a sprint, leave or a filter on created and due dates. Both ends can be typed in the locale’s format or picked on a calendar that previews the range as the pointer or focus moves; presets cover common periods. The value is { start, end }, inclusive ISO dates. Import from @rookcom/monarch-react/scheduling.

Use when

  • Report and analytics periods with presets (Last 7 days, Last month).
  • Filtering lists by a created, due or updated date range.
  • Booking a span of days (leave, sprints, campaigns) with a minimum or maximum length.

Avoid when

  • Only a few fixed periods and no custom range: use SegmentedControl.
  • Two unrelated dates (a start date and a separate review date): use two DatePickers.

Design principles

  • One control for one period: a single box with two inputs, one calendar, one error.
  • The range is only committed when it is complete and valid, so filters never run on half a range.
  • The calendar previews the range before the second click, and blocks days that would break the length limits.
  • Two months where there is room, one on phones.

API reference

import { DateRangePicker } from '@rookcom/monarch-react/scheduling';
ExportKindRenderingRoot class
DateRangePickercomponentclient.mn-date-range-picker

The ref goes to the root role="group" element.

startName and endName add hidden inputs for form submission.

Generated from the TypeScript declarations of packages/react/src/components/search/date-range-picker.

Properties

value/onValueChange (controlled) or defaultValue; onValueChange receives a complete { start, end } or null.

Presets: { lastDays } (ending today), { nextDays } (starting today), { months } (0 = this calendar month, -1 = last), or a fixed { range }. Presets are clipped to min and max (with max today, “This month” is month to date) and disabled when what is left breaks the limits.

minDays/maxDays count both ends: Monday to Sunday is 7 days.

onValidationChange reports a date error, end-before-start, too-short, too-long or null.

DateRangePicker

Two dates that bound a period: typed in the locale's format, or picked on a one- or two-month calendar with a live preview of the range, plus quick picks such as "Last 7 days". Enforces min/max dates and a minimum and maximum length. The value is `{ start, end }` as ISO `YYYY-MM-DD`, inclusive.

PropTypeDescription
childrenReactNode
classNamestring
clearablebooleanShow a clear button while there is a value. Default true.
defaultValueDateRange | nullInitial range (uncontrolled).
disabledboolean
endNamestringForm field name for the end date.
getDayInfo((date: IsoDate) => MiniMonthDayInfo | undefined)Dots and descriptions for calendar days (see MiniMonth).
idstring
invalidbooleanMarks the field invalid. Inside a Field, the Field's `invalid` is used.
isDateDisabled((date: IsoDate) => boolean)Blocks extra dates as a start or an end.
localestringBCP 47 locale. Default: the runtime's. Pass it for server rendering.
maxstringLatest allowed date.
maxDaysnumberLongest allowed range in days, counting both ends (e.g. 366 for reports).
messagesPartial<DateRangePickerMessages>Text for translation.
minstringEarliest allowed date.
minDaysnumberShortest allowed range in days, counting both ends.
numberOfMonths1 | "auto" | 2Months shown in the calendar. `'auto'` (default) shows two on wide screens and one on narrow.
onOpenChange((open: boolean) => void)
onValidationChange((error: DateRangeValidationError | null) => void)Called when the built-in validation result changes (`null` when valid).
onValueChange((value: DateRange | null) => void)Called with a complete, valid range, or `null` when cleared.
openbooleanWhether the calendar is open (controlled).
presetsreadonly DateRangePreset[]Quick picks such as "Last 7 days", shown beside the calendar.
readOnlyboolean
requiredboolean
showErrorsbooleanRender the built-in error message. Default true.
showWeekNumbersbooleanShow ISO week numbers in the calendar.
size"sm" | "md" | "lg"Control height. Default `md`.
startNamestringForm field name for the start date (`YYYY-MM-DD`).
todaystringToday's date. Default: the device's.
valueDateRange | nullThe range (controlled), or `null` for none.
weekStartsOnWeekdayFirst day of the calendar week. Default: from the locale.

Variants

PropValuesDescription
numberOfMonths'auto''1''2'auto shows two months from 640px wide, one below. Default auto.
presets'none''list'Quick picks beside the calendar (above it on phones).
size'sm''md''lg'Control height. Default md.

States

StateExposed asBehaviour
Pickingdata-preview on calendar cellsAfter the first day: the start is marked and the range previews to the hovered or focused day.
Selected rangearia-selected="true", data-in-rangeA tinted band with filled ends.
Invalidaria-invalid="true", data-invalidA date error, end before start, or a range too short or too long; one message explains it.
Disableddisabled, data-disabledBoth inputs and the calendar button.

Interaction behaviour

  • Typed dates are read on blur and Enter; the value changes once both ends are valid.
  • In the calendar, the first pick sets the start, the second the end; picking an earlier day second swaps them. The calendar then closes and focus returns to the start field.
  • After the first pick a polite announcement says to choose the end date.
  • A preset sets both ends at once and closes the calendar; the current preset is pressed.
  • Escape closes the calendar and discards a half-picked range.

Keyboard support

KeysAction
TabStart field, end field, clear button, calendar button.
↓ (in a field)Open the calendar.
Arrows, Home/End, Page Up/DownMove in the calendar; the preview follows focus.
Enter / SpacePick the start, then the end.
EscapeClose the calendar.

Accessibility

Role
group of two textboxes, with a button that opens a dialog containing one or two grids
Accessible name
The group is named by FieldLabel (or aria-label); the inputs are "<label> start date" and "<label> end date"; the button "Choose dates" or "Change dates, <start> to <end>".
  • Every day in the range is aria-selected; preview days are not, so only the real selection is announced as selected.
  • Days blocked by the length limits are aria-disabled while picking.
  • Presets are toggle buttons in a labelled group.
  • One error message, linked to both inputs and announced politely.

Responsive behaviour

  • The box fills its container; each input shrinks evenly.
  • Two months side by side from 640px; one month below, so it fits a 320px screen.
  • Below 640px, presets move above the calendar as wrapping chips.

Theme support

  • Input tokens for the box and MiniMonth tokens for the calendar; the range band is accent-subtle.
  • Forced-colours mode outlines the range and the pressed preset; reduced motion removes transitions.

Do and don't

Do

  • Send start and end as inclusive dates; if the API wants an exclusive end, add one day on the way out.
  • Set maxDays when the backend limits the range, so the calendar blocks it up front.
  • Offer presets for the periods people use most.

Don't

  • Do not run a query on every keystroke; onValueChange only fires for a complete, valid range.
  • Do not convert the dates to local-time Date objects to compute days; the strings are calendar dates.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsField, Popover, MiniMonth

Testing coverage

  • Labelled group with start and end inputs and a dialog button; axe clean.
  • Typed ranges commit only when both ends are valid; end before start and length errors.
  • Calendar picking with hover preview, closing and returning focus; keyboard picking with swap and focus-driven preview.
  • Days outside the length limits disabled while picking.
  • Presets (lastDays, nextDays, months, range), disabled when they break limits, pressed when current.
  • min/max dates; two months with a range across them.
  • Clear, controlled value, hidden inputs, disabled.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/date-range-picker and the open calendar (overlays/date-range-picker-*.png); Cross-browser axe: /components/date-range-picker

Tests: packages/react/src/components/search/date-range-picker