or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

date-field-state.mddate-picker-state.mddate-range-picker-state.mdindex.mdtime-field-state.md
tile.json

tessl/npm-react-stately--datepicker

React state management hooks for date picker components with internationalization and accessibility support.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@react-stately/datepicker@3.15.x

To install, run

npx @tessl/cli install tessl/npm-react-stately--datepicker@3.15.0

index.mddocs/

@react-stately/datepicker

@react-stately/datepicker is a React state management library that provides hooks for date picker components as part of Adobe's React Spectrum ecosystem. It offers cross-platform state management functionality through hooks that handle date selection, validation, formatting, and overlay state management with full internationalization support.

Package Information

  • Package Name: @react-stately/datepicker
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @react-stately/datepicker

Core Imports

import { 
  useDatePickerState, 
  useDateFieldState, 
  useDateRangePickerState, 
  useTimeFieldState,
  type DatePickerState,
  type DatePickerStateOptions,
  type DateFieldState,
  type DateFieldStateOptions,
  type DateRangePickerState,
  type DateRangePickerStateOptions,
  type TimeFieldState,
  type TimeFieldStateOptions,
  type DateSegment,
  type SegmentType,
  type FormatterOptions
} from "@react-stately/datepicker";

For CommonJS:

const { 
  useDatePickerState, 
  useDateFieldState, 
  useDateRangePickerState, 
  useTimeFieldState 
} = require("@react-stately/datepicker");

Basic Usage

import { useDatePickerState, useDateFieldState } from "@react-stately/datepicker";
import { CalendarDate, createCalendar } from "@internationalized/date";

function MyDatePicker() {
  const state = useDatePickerState({
    defaultValue: new CalendarDate(2023, 6, 15),
    onChange: (value) => console.log("Selected:", value?.toString()),
    granularity: 'day'
  });

  return (
    <div>
      <button onClick={() => state.setOpen(!state.isOpen)}>
        {state.value?.toString() || "Select date"}
      </button>
      {state.isOpen && (
        <div>Calendar would be rendered here</div>
      )}
    </div>
  );
}

function MyDateField() {
  const state = useDateFieldState({
    locale: 'en-US',
    createCalendar,
    defaultValue: new CalendarDate(2023, 6, 15),
    onChange: (value) => console.log("Field value:", value?.toString())
  });

  return (
    <div>
      {state.segments.map((segment, i) => (
        <span key={i} aria-label={segment.type}>
          {segment.text}
        </span>
      ))}
    </div>
  );
}

Architecture

@react-stately/datepicker is built around several key components:

  • State Management Hooks: Four specialized hooks for different date/time input scenarios
  • Internationalization Support: Built on @internationalized/date for cross-calendar system support
  • Form Integration: Extends @react-stately/form for validation and error handling
  • Overlay Management: Integrates with @react-stately/overlays for popover state
  • Segment-based Editing: Individual editable segments for precise date/time input
  • Type Safety: Full TypeScript support with generic date value types

Capabilities

Date Picker State

Core state management for date picker components that combine a text field with a calendar popover. Handles date selection, time selection, validation, and overlay state.

function useDatePickerState<T extends DateValue = DateValue>(
  props: DatePickerStateOptions<T>
): DatePickerState;

interface DatePickerStateOptions<T extends DateValue> extends DatePickerProps<T> {
  /**
   * Determines whether the date picker popover should close automatically when a date is selected.
   * @default true
   */
  shouldCloseOnSelect?: boolean | (() => boolean);
}

interface DatePickerState extends OverlayTriggerState, FormValidationState {
  /** The currently selected date. */
  value: DateValue | null;
  /** The default date. */
  defaultValue: DateValue | null;
  /** Sets the selected date. */
  setValue(value: DateValue | null): void;
  /**
   * The date portion of the value. This may be set prior to `value` if the user has
   * selected a date but has not yet selected a time.
   */
  dateValue: DateValue | null;
  /** Sets the date portion of the value. */
  setDateValue(value: DateValue): void;
  /**
   * The time portion of the value. This may be set prior to `value` if the user has
   * selected a time but has not yet selected a date.
   */
  timeValue: TimeValue | null;
  /** Sets the time portion of the value. */
  setTimeValue(value: TimeValue): void;
  /** The granularity for the field, based on the `granularity` prop and current value. */
  granularity: Granularity;
  /** Whether the date picker supports selecting a time, according to the `granularity` prop and current value. */
  hasTime: boolean;
  /** Whether the calendar popover is currently open. */
  isOpen: boolean;
  /** Sets whether the calendar popover is open. */
  setOpen(isOpen: boolean): void;
  /**
   * The current validation state of the date picker, based on the `validationState`, `minValue`, and `maxValue` props.
   * @deprecated Use `isInvalid` instead.
   */
  validationState: ValidationState | null;
  /** Whether the date picker is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */
  isInvalid: boolean;
  /** Formats the selected value using the given options. */
  formatValue(locale: string, fieldOptions: FieldOptions): string;
  /** Gets a formatter based on state's props. */
  getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;
}

Date Picker State

Date Field State

State management for date field components with individually editable segments. Each part of a date value is displayed in a separate editable segment (year, month, day, etc.).

function useDateFieldState<T extends DateValue = DateValue>(
  props: DateFieldStateOptions<T>
): DateFieldState;

interface DateFieldStateOptions<T extends DateValue = DateValue> extends DatePickerProps<T> {
  /**
   * The maximum unit to display in the date field.
   * @default 'year'
   */
  maxGranularity?: 'year' | 'month' | Granularity;
  /** The locale to display and edit the value according to. */
  locale: string;
  /**
   * A function that creates a Calendar object for a given calendar identifier.
   * Such a function may be imported from the @internationalized/date package.
   */
  createCalendar: (name: CalendarIdentifier) => Calendar;
}

interface DateFieldState extends FormValidationState {
  /** The current field value. */
  value: DateValue | null;
  /** The default field value. */
  defaultValue: DateValue | null;
  /** The current value, converted to a native JavaScript Date object. */
  dateValue: Date;
  /** The calendar system currently in use. */
  calendar: Calendar;
  /** Sets the field's value. */
  setValue(value: DateValue | null): void;
  /** A list of segments for the current value. */
  segments: DateSegment[];
  /** A date formatter configured for the current locale and format. */
  dateFormatter: DateFormatter;
  /**
   * The current validation state of the date field, based on the `validationState`, `minValue`, and `maxValue` props.
   * @deprecated Use `isInvalid` instead.
   */
  validationState: ValidationState | null;
  /** Whether the date field is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */
  isInvalid: boolean;
  /** The granularity for the field, based on the `granularity` prop and current value. */
  granularity: Granularity;
  /** The maximum date or time unit that is displayed in the field. */
  maxGranularity: 'year' | 'month' | Granularity;
  /** Whether the field is disabled. */
  isDisabled: boolean;
  /** Whether the field is read only. */
  isReadOnly: boolean;
  /** Whether the field is required. */
  isRequired: boolean;
  /** Increments the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */
  increment(type: SegmentType): void;
  /** Decrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */
  decrement(type: SegmentType): void;
  /**
   * Increments the given segment by a larger amount, rounding it to the nearest increment.
   * The amount to increment by depends on the field, for example 15 minutes, 7 days, and 5 years.
   * Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.
   */
  incrementPage(type: SegmentType): void;
  /**
   * Decrements the given segment by a larger amount, rounding it to the nearest increment.
   * The amount to decrement by depends on the field, for example 15 minutes, 7 days, and 5 years.
   * Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.
   */
  decrementPage(type: SegmentType): void;
  /** Sets the value of the given segment. */
  setSegment(type: 'era', value: string): void;
  setSegment(type: SegmentType, value: number): void;
  /** Updates the remaining unfilled segments with the placeholder value. */
  confirmPlaceholder(): void;
  /** Clears the value of the given segment, reverting it to the placeholder. */
  clearSegment(type: SegmentType): void;
  /** Formats the current date value using the given options. */
  formatValue(fieldOptions: FieldOptions): string;
  /** Gets a formatter based on state's props. */
  getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;
}

Date Field State

Date Range Picker State

State management for date range picker components that allow users to select a start and end date. Combines two date fields with a range calendar popover.

function useDateRangePickerState<T extends DateValue = DateValue>(
  props: DateRangePickerStateOptions<T>
): DateRangePickerState;

interface DateRangePickerStateOptions<T extends DateValue = DateValue> extends DateRangePickerProps<T> {
  /**
   * Determines whether the date range picker popover should close automatically when a date range is selected.
   * @default true
   */
  shouldCloseOnSelect?: boolean | (() => boolean);
}

interface DateRangePickerState extends OverlayTriggerState, FormValidationState {
  /** The currently selected date range. */
  value: RangeValue<DateValue | null>;
  /** The default date range. */
  defaultValue: DateRange | null;
  /** Sets the selected date range. */
  setValue(value: DateRange | null): void;
  /** The date range portion of the value. This may be set prior to `value` if the user has selected dates but not times. */
  dateRange: RangeValue<DateValue | null> | null;
  /** Sets the date range portion of the value. */
  setDateRange(value: DateRange): void;
  /** The time range portion of the value. This may be set prior to `value` if the user has selected times but not dates. */
  timeRange: RangeValue<TimeValue | null> | null;
  /** Sets the time range portion of the value. */
  setTimeRange(value: TimeRange): void;
  /** Sets the date for either the start or end of the range. */
  setDate(part: 'start' | 'end', value: DateValue | null): void;
  /** Sets the time for either the start or end of the range. */
  setTime(part: 'start' | 'end', value: TimeValue | null): void;
  /** Sets the date and time for either the start or end of the range. */
  setDateTime(part: 'start' | 'end', value: DateValue | null): void;
  /** The granularity for the field, based on the `granularity` prop and current value. */
  granularity: Granularity;
  /** Whether the date range picker supports selecting a time, according to the `granularity` prop and current value. */
  hasTime: boolean;
  /** Whether the calendar popover is currently open. */
  isOpen: boolean;
  /** Sets whether the calendar popover is open. */
  setOpen(isOpen: boolean): void;
  /**
   * The current validation state of the date range picker, based on the `validationState`, `minValue`, and `maxValue` props.
   * @deprecated Use `isInvalid` instead.
   */
  validationState: ValidationState | null;
  /** Whether the date range picker is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */
  isInvalid: boolean;
  /** Formats the selected value using the given options. */
  formatValue(locale: string, fieldOptions: FieldOptions): {start: string, end: string} | null;
  /** Gets a formatter based on state's props. */
  getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;
}

Date Range Picker State

Time Field State

State management for time field components that allow users to enter and edit time values. Each part of a time value is displayed in individually editable segments.

function useTimeFieldState<T extends TimeValue = TimeValue>(
  props: TimeFieldStateOptions<T>
): TimeFieldState;

interface TimeFieldStateOptions<T extends TimeValue = TimeValue> extends TimePickerProps<T> {
  /** The locale to display and edit the value according to. */
  locale: string;
}

interface TimeFieldState extends DateFieldState {
  /** The current time value as a Time object. */
  timeValue: Time;
}

Time Field State

Props Interfaces

// Base props interfaces from @react-types/datepicker
interface DatePickerProps<T extends DateValue> {
  /** The current value (controlled). */
  value?: T | null;
  /** The default value (uncontrolled). */
  defaultValue?: T | null;
  /** Handler that is called when the value changes. */
  onChange?: (value: MappedDateValue<T> | null) => void;
  /** The minimum allowed date that a user may select. */
  minValue?: DateValue;
  /** The maximum allowed date that a user may select. */
  maxValue?: DateValue;
  /** Callback that is called for each date of the calendar. If true, the date is unavailable. */
  isDateUnavailable?: (date: DateValue) => boolean;
  /** Whether the calendar is disabled. */
  isDisabled?: boolean;
  /** Whether the calendar is read only. */
  isReadOnly?: boolean;
  /** A placeholder date that influences the format of the placeholder shown when no value is selected. */
  placeholderValue?: T;
  /** Determines the smallest unit that is displayed in the date picker. */
  granularity?: Granularity;
  /** Whether to hide the time zone abbreviation. */
  hideTimeZone?: boolean;
  /** Whether to display the time in 12 or 24 hour format. */
  hourCycle?: 12 | 24;
  /** Whether to always show leading zeros in the month, day, and hour fields. */
  shouldForceLeadingZeros?: boolean;
  /** Whether the element should receive focus on render. */
  autoFocus?: boolean;
  /** The name of the input element, used when submitting an HTML form. */
  name?: string;
  /** Whether user input is required on the input before form submission. */
  isRequired?: boolean;
  /** Whether the input value is invalid. */
  isInvalid?: boolean;
  /** The current validation state of the date picker. */
  validationState?: ValidationState;
  /** Controls the behavior of paging. */
  pageBehavior?: 'visible' | 'single';
  /** The day that starts the week. */
  firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';
}

interface DateRangePickerProps<T extends DateValue> {
  /** The current value (controlled). */
  value?: RangeValue<T> | null;
  /** The default value (uncontrolled). */
  defaultValue?: RangeValue<T> | null;
  /** Handler that is called when the value changes. */
  onChange?: (value: RangeValue<MappedDateValue<T>> | null) => void;
  /** The minimum allowed date that a user may select. */
  minValue?: DateValue;
  /** The maximum allowed date that a user may select. */
  maxValue?: DateValue;
  /** Callback that is called for each date of the calendar. If true, the date is unavailable. */
  isDateUnavailable?: (date: DateValue) => boolean;
  /** Whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. */
  allowsNonContiguousRanges?: boolean;
  /** Whether the calendar is disabled. */
  isDisabled?: boolean;
  /** Whether the calendar is read only. */
  isReadOnly?: boolean;
  /** A placeholder date that influences the format of the placeholder shown when no value is selected. */
  placeholderValue?: T;
  /** Determines the smallest unit that is displayed in the date picker. */
  granularity?: Granularity;
  /** Whether to hide the time zone abbreviation. */
  hideTimeZone?: boolean;
  /** Whether to display the time in 12 or 24 hour format. */
  hourCycle?: 12 | 24;
  /** Whether to always show leading zeros in the month, day, and hour fields. */
  shouldForceLeadingZeros?: boolean;
  /** Whether the element should receive focus on render. */
  autoFocus?: boolean;
  /** The name of the start date input element, used when submitting an HTML form. */
  startName?: string;
  /** The name of the end date input element, used when submitting an HTML form. */
  endName?: string;
  /** Whether user input is required on the input before form submission. */
  isRequired?: boolean;
  /** Whether the input value is invalid. */
  isInvalid?: boolean;
  /** The current validation state of the date range picker. */
  validationState?: ValidationState;
  /** Controls the behavior of paging. */
  pageBehavior?: 'visible' | 'single';
  /** The day that starts the week. */
  firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';
}

interface TimePickerProps<T extends TimeValue> {
  /** The current value (controlled). */
  value?: T | null;
  /** The default value (uncontrolled). */
  defaultValue?: T | null;
  /** Handler that is called when the value changes. */
  onChange?: (value: MappedTimeValue<T> | null) => void;
  /** Whether to display the time in 12 or 24 hour format. */
  hourCycle?: 12 | 24;
  /** Determines the smallest unit that is displayed in the time picker. */
  granularity?: 'hour' | 'minute' | 'second';
  /** Whether to hide the time zone abbreviation. */
  hideTimeZone?: boolean;
  /** Whether to always show leading zeros in the hour field. */
  shouldForceLeadingZeros?: boolean;
  /** A placeholder time that influences the format of the placeholder shown when no value is selected. */
  placeholderValue?: T;
  /** The minimum allowed time that a user may select. */
  minValue?: TimeValue | null;
  /** The maximum allowed time that a user may select. */
  maxValue?: TimeValue | null;
  /** Whether the field is disabled. */
  isDisabled?: boolean;
  /** Whether the field is read only. */
  isReadOnly?: boolean;
  /** Whether the element should receive focus on render. */
  autoFocus?: boolean;
  /** The name of the input element, used when submitting an HTML form. */
  name?: string;
  /** Whether user input is required on the input before form submission. */
  isRequired?: boolean;
  /** Whether the input value is invalid. */
  isInvalid?: boolean;
  /** The current validation state of the time picker. */
  validationState?: ValidationState;
}

Core Types

// Date value types from @internationalized/date
type DateValue = CalendarDate | CalendarDateTime | ZonedDateTime;
type TimeValue = Time | CalendarDateTime | ZonedDateTime;
type Granularity = 'day' | 'hour' | 'minute' | 'second';

// Mapped types for controlled values
type MappedDateValue<T> =
  T extends ZonedDateTime ? ZonedDateTime :
  T extends CalendarDateTime ? CalendarDateTime :
  T extends CalendarDate ? CalendarDate :
  never;

type MappedTimeValue<T> =
  T extends ZonedDateTime ? ZonedDateTime :
  T extends CalendarDateTime ? CalendarDateTime :
  T extends Time ? Time :
  never;

// Calendar types from @internationalized/date
type CalendarIdentifier = 'buddhist' | 'ethiopic' | 'ethioaa' | 'coptic' | 'hebrew' | 'indian' | 'islamic-civil' | 'islamic-tbla' | 'islamic-umalqura' | 'japanese' | 'persian' | 'roc' | 'gregory';

interface Calendar {
  identifier: CalendarIdentifier;
  toDate(date: DateValue): Date;
  fromDate(date: Date): CalendarDate;
  getDaysInMonth(date: DateValue): number;
  getMonthsInYear(date: DateValue): number;
  getYearsInEra(date: DateValue): number;
  getEras(): string[];
  balanceDate(date: DateValue): CalendarDate;
}

interface DateFormatter {
  formatToParts(date: Date): Intl.DateTimeFormatPart[];
  format(date: Date): string;
  formatRange(startDate: Date, endDate: Date): string;
  formatRangeToParts(startDate: Date, endDate: Date): Intl.DateTimeFormatPart[];
}

// Core classes from @internationalized/date
interface CalendarDate {
  readonly calendar: Calendar;
  readonly era: string;
  readonly year: number;
  readonly month: number;
  readonly day: number;
  copy(): CalendarDate;
  add(duration: DateDuration): CalendarDate;
  subtract(duration: DateDuration): CalendarDate;
  set(fields: DateFields): CalendarDate;
  cycle(field: DateField, amount: number): CalendarDate;
  toDate(timeZone: string): Date;
  toString(): string;
  compare(other: DateValue): number;
}

interface CalendarDateTime {
  readonly calendar: Calendar;
  readonly era: string;
  readonly year: number;
  readonly month: number;
  readonly day: number;
  readonly hour: number;
  readonly minute: number;
  readonly second: number;
  readonly millisecond: number;
  copy(): CalendarDateTime;
  add(duration: DateTimeDuration): CalendarDateTime;
  subtract(duration: DateTimeDuration): CalendarDateTime;
  set(fields: DateTimeFields): CalendarDateTime;
  cycle(field: DateField, amount: number): CalendarDateTime;
  toDate(timeZone: string): Date;
  toString(): string;
  compare(other: DateValue): number;
}

interface ZonedDateTime {
  readonly calendar: Calendar;
  readonly era: string;
  readonly year: number;
  readonly month: number;
  readonly day: number;
  readonly hour: number;
  readonly minute: number;
  readonly second: number;
  readonly millisecond: number;
  readonly timeZone: string;
  readonly offset: number;
  copy(): ZonedDateTime;
  add(duration: DateTimeDuration): ZonedDateTime;
  subtract(duration: DateTimeDuration): ZonedDateTime;
  set(fields: DateTimeFields): ZonedDateTime;
  cycle(field: DateField, amount: number): ZonedDateTime;
  toDate(): Date;
  toString(): string;
  compare(other: DateValue): number;
}

interface Time {
  readonly hour: number;
  readonly minute: number;
  readonly second: number;
  readonly millisecond: number;
  copy(): Time;
  add(duration: TimeDuration): Time;
  subtract(duration: TimeDuration): Time;
  set(fields: TimeFields): Time;
  cycle(field: TimeField, amount: number): Time;
  toString(): string;
  compare(other: TimeValue): number;
}

// Duration and field types
interface DateDuration {
  years?: number;
  months?: number;
  weeks?: number;
  days?: number;
}

interface TimeDuration {
  hours?: number;
  minutes?: number;
  seconds?: number;
  milliseconds?: number;
}

interface DateTimeDuration extends DateDuration, TimeDuration {}

interface DateFields {
  era?: string;
  year?: number;
  month?: number;
  day?: number;
}

interface TimeFields {
  hour?: number;
  minute?: number;
  second?: number;
  millisecond?: number;
}

interface DateTimeFields extends DateFields, TimeFields {}

type DateField = keyof DateFields;
type TimeField = keyof TimeFields;

// Segment types for date field editing
type SegmentType = 'era' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName';

interface DateSegment {
  type: SegmentType;
  text: string;
  value?: number;
  minValue?: number;
  maxValue?: number;
  isPlaceholder: boolean;
  placeholder: string;
  isEditable: boolean;
}

// Range types for date range pickers
interface RangeValue<T> {
  start: T;
  end: T;
}

type DateRange = RangeValue<DateValue>;
type TimeRange = RangeValue<TimeValue>;

// Validation and formatting
interface FieldOptions {
  year?: 'numeric' | '2-digit';
  month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long';
  day?: 'numeric' | '2-digit';
  hour?: 'numeric' | '2-digit';
  minute?: 'numeric' | '2-digit';
  second?: 'numeric' | '2-digit';
}

interface FormatterOptions {
  timeZone?: string;
  hideTimeZone?: boolean;
  granularity?: Granularity;
  maxGranularity?: 'year' | 'month' | Granularity;
  hourCycle?: 12 | 24;
  showEra?: boolean;
  shouldForceLeadingZeros?: boolean;
}

// Validation and state types from React Stately ecosystem
type ValidationState = 'valid' | 'invalid';

interface FormValidationState {
  /** Whether the input value is invalid according to validation rules */
  isInvalid: boolean;
  /** The current validation state @deprecated Use isInvalid instead */
  validationState: ValidationState | null;
  /** Validation errors */
  validationErrors: string[];
  /** Commit validation state changes */
  commitValidation(): void;
  /** Update validation state */
  updateValidation(result: ValidationResult): void;
  /** Display validation state for UI rendering */
  displayValidation: {
    isInvalid: boolean;
    validationErrors: string[];
  };
}

interface OverlayTriggerState {
  /** Whether the overlay is currently open */
  isOpen: boolean;
  /** Sets whether the overlay is open */
  setOpen(isOpen: boolean): void;
  /** Opens the overlay */
  open(): void;
  /** Closes the overlay */
  close(): void;
  /** Toggles the overlay open/closed state */
  toggle(): void;
}

interface ValidationResult {
  /** Whether the value is invalid */
  isInvalid: boolean;
  /** Array of validation error messages */
  validationErrors: string[];
  /** Detailed validation state for different error types */
  validationDetails: ValidityState;
}