EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
DateInput·component·@astryxdesign/core

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.

Open in Playground @astryxdesign/core/DateRangeInput

Showcases and examples

3 documented examples

Date Range Input

A date range picker with a button trigger and dual-month calendar popover with preset ranges.

Preview loads on approachPreview loads on approach
Exact source · date-range-input-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {useState} from 'react';
import {DateRangeInput} from '@astryxdesign/core/DateRangeInput';
import type {DateRange} from '@astryxdesign/core/DateRangeInput';
import type {ISODateString} from '@astryxdesign/core/Calendar';
import {Stack} from '@astryxdesign/core/Layout';

function daysAgo(n: number): ISODateString {
  const d = new Date();
  d.setDate(d.getDate() - n);
  return d.toISOString().slice(0, 10) as ISODateString;
}

function today(): ISODateString {
  return new Date().toISOString().slice(0, 10) as ISODateString;
}

const presets = [
  {label: 'Last 7 days', getRange: () => ({start: daysAgo(7), end: today()})},
  {label: 'Last 30 days', getRange: () => ({start: daysAgo(30), end: today()})},
];

export default function DateRangeInputShowcase() {
  const [range, setRange] = useState<DateRange | null>(null);

  return (
    <Stack direction="vertical" width="100%" style={{maxWidth: 400}}>
      <DateRangeInput
        label="Date range"
        value={range}
        onChange={setRange}
        presets={presets}
      />
    </Stack>
  );
}

Usage

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.

  • 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.
  • Use DateRangeInput when only a single date is needed; use DateInput instead.
  • Hide the label without surrounding context that makes the purpose obvious.
  • 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.

Typed props

PropType and behavior
labelstring · required
Label text.
isLabelHiddenboolean · default false
Visually hide the label.
descriptionstring
Helper text displayed below the label.
isOptionalboolean · default false
Show an "(optional)" indicator.
isRequiredboolean · default false
Mark the field as required.
isDisabledboolean · default false
Disable the trigger and picker.
disabledMessagestring
Explains 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.
valueDateRange | null · required
Selected 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) => void · required
Callback 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.
isLoadingboolean · default false
Whether the input is in a loading state. Disables interaction and shows a spinner.
minISODateString
Minimum 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/Calendar or use as ISODateString` if computing the value dynamically.
maxISODateString
Maximum 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.
maxRangeSpannumber
Maximum 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).
minRangeSpannumber
Minimum 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.
hasClearboolean · default true
Shows a clear button when a range is selected.
placeholderstring · default 'Select date range'
Placeholder text when no range is selected.
size'sm' | 'md' | 'lg' · default 'md'
Size of the trigger.
status{type: 'warning' | 'error' | 'success', message?: string}
Status indicator for error, warning, or success states.
statusVariant'attached' | 'detached' | 'tooltip' · default '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.
labelTooltipstring
Tooltip text via info icon at label end.
numberOfMonths1 | 2 · default 2
Number of months in the calendar.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6 | 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' · default 0
First day of week in the calendar. A number (0 = Sunday to 6 = Saturday) or a three-letter day name.
widthSizeValue
Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.
xstyleStyleXStyles
StyleX styles for layout customization.

Anatomy

Label · required

Text above the trigger describing what date range is expected.

Field surface · required

Bordered control containing the calendar toggle, range trigger, and end affordances.

Trigger button · required

A button showing the formatted range or placeholder. Clicking opens the popover.

Calendar icon · required

A trailing icon that also opens the popover.

Calendar popover · required

A dual-month calendar grid with range selection and hover preview.

Preset sidebar · optional

A list of preset range options beside the calendar.

Preset button · optional

A quick-select action for one preset range, reflecting current and disabled states.

Clear button · optional

A × button that resets the range to null.

Status message · optional

An error, warning, or success message below the trigger.

Theming

Targets

astryx-date-range-input

Visual props: size, status

States: disabled

astryx-date-range-input-toggle-icon

States: state

astryx-date-range-input-clear-icon

Deprecated; use input-clear-icon.

astryx-date-range-input-presets
astryx-date-range-input-preset

States: selected, disabled