Skip to content

Components · Date, time and scheduling

DatePicker

A date field: type in the locale’s format or pick from a calendar popover, with presets, min/max and Field errors.

@rookcom/monarch-react/schedulingComponent

Due date with quick picks

Type a date or pick one. Value: none

Usage examples

Min, max and an error

Sizes and formats

Inside a dialog

Purpose

Lets people enter one calendar date in a form, by typing it the way their locale writes dates or by picking it from a calendar. The value is an ISO YYYY-MM-DD string with no time zone, so it never shifts by a day. Replaces native type="date" inputs, which render differently in every browser and cannot show presets. Import from @rookcom/monarch-react/scheduling.

Use when

  • Due dates, start dates, birthdays, renewal and expiry dates in forms and editors.
  • A date with quick picks such as Today, Tomorrow and In a week.

Avoid when

  • A date and a time: use DateTimePicker.
  • A period: use DateRangePicker.
  • Showing a date read-only: format it with RelativeTime or plain text.

Design principles

  • Typing is first-class: the field accepts the locale’s numeric order, month names, ISO and digits without separators.
  • Invalid text is kept so it can be fixed, and explained with the expected format; the value only changes to a valid date.
  • The calendar is the same MiniMonth grid everywhere, with the same keyboard model.
  • No time zones: a date is a calendar date.

API reference

import { DatePicker } from '@rookcom/monarch-react/scheduling';
ExportKindRenderingRoot class
DatePickercomponentclient.mn-date-picker

The ref goes to the text <input>; native input props (id, aria-*, onBlur, autoFocus, …) go there too. className styles the wrapper.

With name, a hidden input submits the ISO value; the visible input has no name.

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

Properties

value/onValueChange (controlled) or defaultValue; onValueChange receives a valid ISO date or null, never invalid text.

presets: { label, days } relative to today or { label, date } fixed.

onValidationChange reports invalid, before-min, after-max, unavailable or null; set showErrors={false} to render your own FieldError.

messages translates every string, including the error texts.

DatePicker

A date field: type a date in the locale's format, or pick it from a calendar popover with optional quick picks. The value is an ISO `YYYY-MM-DD` string with no time or time zone. Validates min, max and disabled dates, and reports errors through Field.

PropTypeDescription
childrenReactNode
classNamestringClass for the outer wrapper (the input itself is `.mn-date-picker__input`).
clearablebooleanShow a clear button while there is a value. Default true.
defaultValuestring | nullInitial date (uncontrolled).
disabledboolean
formatOptionsIntl.DateTimeFormatOptionsDisplay format of the text. Default: the locale's numeric date (`04/11/2026`).
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. Built-in errors also set it.
isDateDisabled((date: IsoDate) => boolean)Blocks extra dates (weekends, holidays).
localestringBCP 47 locale for typing, display and the calendar. Default: the runtime's. Pass it for server rendering.
maxstringLatest allowed date.
messagesPartial<DatePickerMessages>Text for translation.
minstringEarliest allowed date. Earlier typed dates show an error; earlier days are disabled.
onOpenChange((open: boolean) => void)Called when the calendar opens or closes.
onValidationChange((error: DateValidationError | null) => void)Called when the built-in validation result changes (`null` when valid).
onValueChange((value: IsoDate | null) => void)Called with a new valid date, or `null` when cleared. Never called with invalid text.
openbooleanWhether the calendar is open (controlled).
presetsreadonly DatePickerPreset[]Quick picks such as Today and Tomorrow, shown beside the calendar.
showErrorsbooleanRender the built-in error message under the field. Default true. Turn off to show your own FieldError.
showWeekNumbersbooleanShow ISO week numbers in the calendar.
size"sm" | "md" | "lg"Control height. Default `md`.
todaystringToday's date. Default: the device's.
valuestring | nullThe date (controlled), `YYYY-MM-DD`, or `null` for none.
weekStartsOnWeekdayFirst day of the calendar week, 0 (Sunday) to 6. Default: from the locale.

Variants

PropValuesDescription
size'sm''md''lg'Control height, as Input. Default md.
presets'none''list'Quick picks beside the calendar (above it on phones).
clearable'true''false'A clear button while there is a value. Default true.
formatOptions'numeric (default)''Intl options'How the value is written in the field, e.g. { dateStyle: "medium" }.

States

StateExposed asBehaviour
Empty–Shows the format hint as placeholder, e.g. DD/MM/YYYY.
Opendata-state="open" on the calendar buttonThe calendar popover is showing.
Invalidaria-invalid="true", data-invalidUnreadable text, a date outside min/max or a disabled date; a message explains why.
Disableddisabled, data-disabledFrom the prop or the Field; the calendar cannot open.
Read-onlyreadonlyThe value can be read and copied; the calendar button is disabled.

Interaction behaviour

  • Typed text is read on blur and on Enter. A valid date is re-formatted in the locale; anything else stays as typed with an error.
  • The calendar button or ↓ in the field opens the calendar, focused on the value (or today). Picking a day or a preset closes it and returns focus to the field.
  • Emptying the field or pressing the clear button sets the value to null.
  • The calendar is a modal popover: it traps focus while open and works inside Dialog and Sheet; Escape closes only the calendar.

Keyboard support

KeysAction
Enter (in the field)Read the typed date.
↓ (in the field)Open the calendar.
Arrows, Home/End, Page Up/DownMove in the calendar (see MiniMonth).
Enter / Space (in the calendar)Pick the focused day and close.
EscapeClose the calendar without changing the value.
TabMoves between the field, the clear and calendar buttons; inside the calendar, between presets, month buttons and the grid.

Accessibility

Role
textbox, with a button that opens a dialog containing a grid
Accessible name
From FieldLabel (or aria-label). The calendar button is named "Choose date" or "Change date, <full date>"; the popover "Choose date".
  • The calendar button has aria-haspopup="dialog" and aria-expanded.
  • Errors are rendered under the field, linked by aria-describedby and announced politely; the field gets aria-invalid.
  • Inside a Field, aria-required, the description and disabled are wired automatically.
  • The format hint is the placeholder and is repeated in the error text, so it is not the only cue.
  • Presets are buttons with aria-pressed for the current value.

Responsive behaviour

  • The field fills its container; the popover never exceeds the viewport minus 1rem.
  • Below 576px, presets move above the calendar as wrapping chips.
  • Larger buttons and presets on touch screens.

Theme support

  • Uses Input’s tokens for the field and MiniMonth’s for the calendar, so every theme and more-contrast mode applies.
  • Transitions are removed under prefers-reduced-motion: reduce.

Do and don't

Do

  • Put it in a Field with a FieldLabel, and pass locale from the user’s settings.
  • Store and send the ISO string as is; format it for display with Intl and timeZone: "UTC".
  • Offer presets for the common choices in task and deadline editors.

Don't

  • Do not build a Date from the value in local time (new Date("2026-11-04") is UTC midnight and shows the previous day west of UTC).
  • Do not show overdue state only by colouring the field; add a Badge or text.
  • Do not use it for a date with a time: use DateTimePicker.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsField, Popover, MiniMonth

The popover is Monarch Popover (Radix), opened as modal.

Testing coverage

  • Labelled textbox wired to Field (required, description); calendar button with aria-haspopup; axe clean.
  • Typed dates in en-GB and en-US order, on blur and Enter; month names; re-formatting.
  • Invalid text kept with an error and aria-invalid, value unchanged, onValidationChange.
  • min, max and disabled dates rejected with messages naming the bound.
  • Calendar opens focused on the value, picks with the keyboard, closes and returns focus; ↓ opens on the typed month; Escape.
  • Presets relative to today, disabled outside the bounds.
  • Clear button and emptying the text; controlled value; hidden input for forms; disabled and read-only.
  • Inside Dialog: the calendar takes focus and Escape closes only the calendar.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/date-picker and the open calendar (overlays/date-picker-*.png); Cross-browser axe: /components/date-picker

Tests: packages/react/src/components/scheduling/date-picker