Skip to content

Date Picker

A date field typed segment by segment, with a calendar popover for picking by sight.

Preview

Date of incident
The day the loss or damage happened.

Installation

pnpm add @syntara/react @syntara/tokens
import { DatePicker, DateRangePicker } from '@syntara/react';

Usage

import { DatePicker } from '@syntara/react';

export function IncidentDate() {
  return <DatePicker label="Date of incident" onChange={(date) => console.log(date?.toString())} />;
}

Examples

Range

DateRangePicker with two months in the popover.

Stay

Date and time

granularity="minute" adds hour and minute segments.

Send at

Invalid and disabled

minValue validation with an error message, and a disabled picker.

Start date
Start date can't be in the past.
Policy renewal

Accessibility

KeysAction
TaborShiftTabMoves between segments, then to the calendar button.
←or→Moves to the previous / next segment.
↑or↓Increments / decrements the focused segment (wraps).
0–9Types into the segment and advances when it's complete.
BackspaceClears the segment, then moves back.
Alt↓Opens the calendar.
EscapeCloses the calendar and returns focus to the field.
Calendar keysInside the popover, the Calendar keyboard applies (arrows, Page Up/Down, Enter).
  • The field is a labelled group; each segment is a spinbutton named by its unit (month, day, year…).
  • Segment order, separators, digits and hour cycle follow the locale.
  • The calendar popover is a dialog labelled by the field label; focus moves into it and back.
  • Empty segments show the placeholder text (mm/dd/yyyy) in text.subtle; the focused segment is highlighted with surface.selected.
  • Every editable segment is at least 24×24px (WCAG 2.5.8) at both densities, without changing the field height.
  • The calendar popover is glass; inside it, days outside the month are hidden and days outside min/max are text.subtle and struck through, so every day number stays legible over any backdrop. Motion follows prefers-reduced-motion.

Guidelines

Do

  • Use for dates near today where seeing the week helps (appointments, deadlines, travel).
  • Say the allowed range in description when you set minValue/maxValue.
  • Use DateRangePicker for start/end pairs so the range stays consistent.

Don’t

  • Don't use the calendar for dates of birth — the field alone is faster to type.
  • Don't format dates yourself — pass DateValue objects and let the locale decide.

API reference

DatePicker

label
ReactNode

Visible label. Use aria-label only when a visible label is impossible.

description
ReactNode

Help text under the field, e.g. the allowed range.

errorMessage
string | ((validation: ValidationResult) => string)

Shown when the value is invalid (out of range, unavailable, missing, or isInvalid).

value / defaultValue
DateValue | null

The date, controlled or initial (CalendarDate, CalendarDateTime or ZonedDateTime).

onChange
(value: DateValue | null) => void

Called when a complete date is entered or picked.

granularity
  • daydefault
  • hour
  • minute
  • second

The smallest unit shown. Anything below 'day' adds time segments.

minValue / maxValue
DateValue

Allowed range; outside values are invalid and disabled in the calendar.

isDateUnavailable
(date: DateValue) => boolean

Dates that can't be chosen; picking one makes the field invalid.

placeholderValue
DateValue

Date the segments start from when stepping with arrow keys, and the calendar's initial month.

hourCycle
12 | 24

Overrides the locale's hour cycle.

shouldForceLeadingZeros
boolean

Pads single-digit months, days and hours (09/05/2026) so segments keep a steady width. Set false for the locale's plain numbers.

Default true

hideTimeZone
boolean

Hides the time zone segment for ZonedDateTime values.

Default false

shouldCloseOnSelect
boolean

Close the popover when a date is picked.

Default true

validationBehavior
  • nativedefault
  • aria

'aria' shows validation errors as the value changes; 'native' waits for form submit.

isRequired / isInvalid / isDisabled / isReadOnly
boolean

Field states; isRequired also shows the label's required marker.

Default false

name
string

Form field name; submits the ISO date string.

DateRangePicker

value / defaultValue
{ start: DateValue; end: DateValue } | null

The range, controlled or initial.

visibleMonths
number

How many months the calendar popover shows side by side.

Default 1

startName / endName
string

Form field names for the two dates.

Tokens

The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.

Colour8
text.defaulttext.subtlesurface.selectedtext.disabledfocus.ringborder.defaultsurface.raisedborder.subtle
Type3
font.bodyfont.size.mdline-height.normal
Space and size4
space.2space.1space.6control-height
Shape3
radius.fieldradius.buttonradius.container
Depth4
glass.opacityglass.blurshadow.overlayhairline
Motion6
motion.duration.fastmotion.easingmotion.duration.normalmotion.easing-outmotion.duration.springmotion.spring
Other2
sheenrim