JGuang

DateRangeInput

DateRangeInput · Astryx

Preview
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

DateRangeInput

DateRangeInput lets users select a start and end date from a dual-month calendar popover. Use it for filtering data by time period, report generation, analytics dashboards, and booking flows.

Installation

npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Requires React 19+, base CSS and a Theme provider. See Setup.

Date Range Input

DateRangeInput lets users select a start and end date from a dual-month calendar popover. Use it for filtering data by time period, report generation, analytics dashboards, and booking flows.

PropTypeDefaultDescription
label *stringLabel text.
isLabelHiddenbooleanfalseVisually hide the label.
descriptionstringHelper text displayed below the label.
isOptionalbooleanfalseShow an "(optional)" indicator.
isRequiredbooleanfalseMark the field as required.
isDisabledbooleanfalseDisable the trigger and picker.
disabledMessagestringExplains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the field focusable via aria-disabled (activation stays blocked). Use this instead of wrapping a disabled DateRangeInput in Tooltip. Disabled controls swallow the hover events an external Tooltip needs.
value *DateRange | nullSelected date range or null. Import the DateRange type from @astryxdesign/core/DateRangeInput; it is {start: ISODateString, end: ISODateString}. Do NOT redeclare your own DateRange type; use the exported one so TypeScript structurally matches.
onChange *(value: DateRange | null) => voidCallback when the range changes. Called with null on clear.
changeAction(value: DateRange | null) => void | Promise<void>Async action fired after onChange. Drives optimistic UI updates via useTransition.
isLoadingbooleanfalseWhether the input is in a loading state. Disables interaction and shows a spinner.
minISODateStringMinimum selectable date. ISODateString is a template literal type (\${number}${number}${number}${number}-${number}${number}-${number}${number}`). Pass a string literal like "2026-01-28", not a runtime string variable. Import it from @astryxdesign/core/Calendaror useas ISODateString` if computing the value dynamically.
maxISODateStringMaximum selectable date. Same template literal type as min: use a YYYY-MM-DD string literal or cast with as ISODateString.
dateConstraintsArray<(date: Date) => boolean>Custom constraint functions to disable specific dates.
maxRangeSpannumberMaximum days a selected range may span, counting both endpoints (7 = a 7-day window, start + 6). Once a start is picked, days beyond this distance are disabled so the range cannot stretch past the cap. Rolling window relative to the start; for fixed calendar bounds use min/max. Constrains selection only; it never rewrites a value already wider than the cap (flag that with status).
minRangeSpannumberMinimum days a selected range must span, counting both endpoints (2 forbids a single-day range). Once a start is picked, days closer than this are disabled. Clicking the start again commits a one-day range when allowed, or cancels the in-progress selection when the minimum is longer. Defaults to 1 (same-day start and end allowed).
presetsArray<DateRangePreset>Preset ranges shown as quick-select options beside the calendar. A preset is disabled when either endpoint violates min, max, or dateConstraints, or when its span violates minRangeSpan or maxRangeSpan.
hasClearbooleantrueShows a clear button when a range is selected.
placeholderstring'Select date range'Placeholder text when no range is selected.
size'sm' | 'md' | 'lg''md'Size of the trigger.
status{type: 'warning' | 'error' | 'success', message?: string}Status indicator for error, warning, or success states.
statusVariant'attached' | 'detached' | 'tooltip''attached'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.
labelTooltipstringTooltip text via info icon at label end.
numberOfMonths1 | 22Number of months in the calendar.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6 | 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'0First day of week in the calendar. A number (0 = Sunday to 6 = Saturday) or a three-letter day name.
widthSizeValueWidth of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.
containerXstyleStyleXStylesStyleX styles for the Field box around the label, control, and status. containerClassName and containerStyle take a class name and inline styles for the same box. No effect (development warning) where no Field box renders: inside InputGroup (style the group) and in a horizontal-labels FormLayout.
controlXstyleStyleXStylesStyleX styles for the visual control box: the bordered element that holds the text, icons, and end controls, never the native input. controlClassName and controlStyle take a class name and inline styles for the same box. Replaces root xstyle, className, and style, which this component does not accept.

Usage guidance

  • Base props such as ref, id, data-, aria-, and DOM event handlers go to the range trigger, the element that is focused and announced. A DOM handler runs after DateRangeInput's own handler for the same event and still receives events it handled (including ones it called preventDefault on), so it cannot cancel built-in behavior.
  • Use presets for common ranges like "Last 7 days" to speed up selection.
  • Use min/max to constrain selectable dates to valid ranges.
  • Keep hasClear enabled (default) so users can reset the filter.
  • Provide clear labels and descriptions so users understand what the range controls.
  • Avoid: Use DateRangeInput when only a single date is needed; use DateInput instead.
  • Avoid: Hide the label without surrounding context that makes the purpose obvious.
  • Avoid: Wrap a disabled DateRangeInput in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.

Theming API

{
  "targets": [
    {
      "className": "astryx-date-range-input",
      "visualProps": [
        "size",
        "status"
      ],
      "states": [
        "disabled"
      ]
    },
    {
      "className": "astryx-date-range-input-toggle-icon",
      "states": [
        "state"
      ]
    },
    {
      "className": "astryx-date-range-input-presets"
    },
    {
      "className": "astryx-date-range-input-preset",
      "states": [
        "selected",
        "disabled"
      ]
    }
  ]
}

Anatomy

  • Label: Text above the trigger describing what date range is expected.
  • Field surface: Bordered control containing the calendar toggle, range trigger, and end affordances.
  • Trigger button: A button showing the formatted range or placeholder. Clicking opens the popover.
  • Calendar icon: A trailing icon that also opens the popover.
  • Calendar popover: A dual-month calendar grid with range selection and hover preview.
  • Preset sidebar: A list of preset range options beside the calendar.
  • Preset button: A quick-select action for one preset range, reflecting current and disabled states.
  • Clear button: A × button that resets the range to null.
  • Status message: An error, warning, or success message below the trigger.

Examples

  • Date Range Input: A date range picker with a button trigger and dual-month calendar popover with preset ranges.
  • DateRangeInput — With Presets: Date range picker with quick-select presets for common periods. Use for analytics dashboards, report filters, or any context where users frequently select standard time windows.
  • DateRangeInput — Validation: Date range input in all three status states: error, warning, and success. Use to surface booking conflicts, flag high-demand periods, or confirm an available range.