RangeDatePicker

Two-month date-range field with blocked-date support.

Overview

  • Select linked start and end dates for bookings, reports, or other date ranges.

Aliases

date range picker

When to use

  • Use RangeDatePicker when the user is choosing a bounded start and end date as one decision.
  • Set min, max, and disabledDates to constrain selection.

When not to use

  • Do not use RangeDatePicker for one-off date fields; use DatePicker.
  • Do not use it for date-plus-time or preset-heavy reporting workflows.

Structural parts

field button

trigger

Shows the current range summary and opens the two-month calendar.

calendar popover

surface

Contains the paired month grids and navigation controls.

calendar day

day

Selectable day cell supporting start, end, and in-range styling.

Public interface

Props
NameTypeDefaultDescription
labelstring—Visible label used for the field or control.
descriptionstring—Provides field guidance associated with the control.
errorstring—Shows a validation error associated with the control.
placeholderstring—Placeholder text shown before a user makes a selection or enters text.
requiredbooleanfalseMarks the control as required.
disabledbooleanfalsePrevents interaction and exposes the disabled state.
namestring—Form field name used for native form submission.
idstring—Sets the control ID for external labels and descriptions.
size'sm' | 'md' | 'lg''md'Sets the component size.
value{ start?: string; end?: string }—Controlled ISO date-only range value.
minstring—Earliest selectable ISO date.
maxstring—Latest selectable ISO date.
disabledDatesstring[]—Explicit ISO dates that cannot be selected.
weekStartsOn0 | 10First day of the week for the month grid.
openbooleanfalseControlled popover open state.
onOpenChange(detail: { open: boolean }) => void—Runs when the calendar opens or closes.
onChange(detail: { value: { start?: string; end?: string } }) => void—Runs when the range changes.
themeThemeContract—Sets the theme used to resolve component styles.
Events
NamePayloadDescription
openchange{ open: boolean }Fires when an overlay-style component opens or closes through user interaction.
change{ value: { start?: string; end?: string } }Fires when the range changes.
Slots
NameDescription
defaultRangeDatePicker is prop-driven and does not expose custom day or panel slots.

Variants, sizes, and states

Variants

  • default: Two linked month grids with start/end range emphasis.

Sizes

  • sm: Compact range field
  • md: Default range field
  • lg: Larger touch-oriented range field

States

  • closed: Calendar hidden
  • open: Calendar visible
  • partial: Start date chosen but end date still pending
  • complete: Start and end dates selected

Accessibility

Semantics

  • Associates the control with its visible label, description, and error.
  • Exposes disabled and required semantics through the underlying form control.
  • Associates a labeled field with the calendar popover.

Keyboard

  • Supports native focus and text entry behavior.
  • Arrow keys move day focus. Home and End move within the week; PageUp and PageDown change months. Escape closes the calendar.

Screen readers

  • Connects visible label, helper text, and error text to the native control.
  • Start, end, blocked, and in-range states remain understandable without relying on color alone.

Checklist

  • Verify that the control has an accessible name.
  • Verify that keyboard focus is visible in every state and size.
  • Identify disabled, selected, and error states with text or symbols as well as color.

Tokens and CSS variables

root

--dk-range-gap
0.5rem
--dk-range-offset
8px

label

--dk-field-label-color
#16181c
--dk-field-label-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-field-label-weight
600

trigger

--dk-range-trigger-bg
#f2f5fb
--dk-range-trigger-fg
#16181c
--dk-range-trigger-border
#95989d
--dk-range-trigger-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-range-trigger-block-size
48px
--dk-range-trigger-inline-padding
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-range-trigger-font-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)

description

--dk-field-description-color
#16181c
--dk-field-description-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

error

--dk-field-error-color
#cc272e
--dk-field-error-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

surface

--dk-range-surface-bg
#f2f5fb
--dk-range-surface-fg
#16181c
--dk-range-surface-border
#95989d
--dk-range-surface-radius
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-range-surface-shadow
0 10px 15px rgba(0, 0, 0, 0.06), 0 4px 6px rgba(0, 0, 0, 0.04)
--dk-range-surface-width
720px
--dk-range-surface-padding
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)

caption

--dk-range-caption-color
#16181c
--dk-range-caption-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-range-caption-weight
700

navButton

--dk-range-nav-bg
#e5e8ed
--dk-range-nav-fg
#16181c
--dk-range-nav-size
36px

weekday

--dk-range-weekday-color
#16181c
--dk-range-weekday-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

day

--dk-range-day-bg
#f2f5fb
--dk-range-day-fg
#16181c
--dk-range-day-selected-bg
#2072e4
--dk-range-day-selected-fg
#ffffff
--dk-range-day-between-bg
#d7e9ff
--dk-range-day-between-fg
#000f4d
--dk-range-day-disabled-fg
#16181c
--dk-range-day-outside-fg
#95989d
--dk-range-day-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-range-day-target
44px
--dk-range-day-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

Implementation notes

  • Range values contain dates without times or time zones.

Examples

Starter

Booking window

A date-range field with a label and guidance.

<RangeDatePicker label="Stay window" description="Choose the booking range." />

Common patterns

Constrained range

Constrain selectable dates with min, max, and disabledDates.

<RangeDatePicker label="Freeze window" min="2026-04-10" max="2026-04-20" disabledDates={['2026-04-16']} />

Edge cases

Controlled range and popover state

Control the range and the surface when app workflow owns selection state.

<RangeDatePicker value={range} open={isOpen} onOpenChange={(detail) => isOpen = detail.open} onChange={(detail) => range = detail.value} />

Mathematical fixtures

Calculated fixtures; browser evidence is not collected. Layout estimates use declared text behavior and maximum token values.

default-md (size=sm)

pass

size=sm

  • Evidence: mathematical
  • Coverage: complete (4 / 4 declared kinds evaluated)
  • Declared: contrast, target, anchoredSurface, layout
  • Evaluated: contrast, target, anchoredSurface, layout
  • Contrast: 98.5 Lc, 76.6 Lc
  • Target: 44 px, 44 px
  • Layout: surface · single-line 0 px single-line estimate; 0 px minimum width
    560 px: pass 720 px: pass
  • Surface: 720 × 360 px

default-md (size=md)

pass

size=md

  • Evidence: mathematical
  • Coverage: complete (4 / 4 declared kinds evaluated)
  • Declared: contrast, target, anchoredSurface, layout
  • Evaluated: contrast, target, anchoredSurface, layout
  • Contrast: 98.5 Lc, 76.6 Lc
  • Target: 48 px, 44 px
  • Layout: surface · single-line 0 px single-line estimate; 0 px minimum width
    560 px: pass 720 px: pass
  • Surface: 720 × 360 px

lg

pass

size=lg

  • Evidence: mathematical
  • Coverage: complete (4 / 4 declared kinds evaluated)
  • Declared: contrast, target, anchoredSurface, layout
  • Evaluated: contrast, target, anchoredSurface, layout
  • Contrast: 98.5 Lc, 76.6 Lc
  • Target: 52 px, 44 px
  • Layout: surface · single-line 0 px single-line estimate; 0 px minimum width
    560 px: pass 720 px: pass
  • Surface: 720 × 360 px