Skip to Content
Hashti Design System
Components

Date Picker

Calendar-driven date selection suite supporting single dates, date ranges, and direct segment inputs.

Date Picker

Hashti’s date and time suite provides an accessible, culturally aware foundation for temporal data entry. Rather than relying on rigid browser defaults, Hashti implements segmented numerical date fields paired with smooth calendar popovers, offering full support for single dates, continuous date ranges, direct segment navigation, and international calendar systems (including the Persian Solar Hijri calendar).

The suite is comprised of:

  • DatePicker: A segmented input with an attached calendar popup for single date selection.
  • DateRangePicker: Paired start/end segmented inputs with a range calendar for booking windows and timespans.
  • DateField & TimeField: Standalone keyboard-navigable segment inputs without a calendar popup.
  • Calendar & RangeCalendar: Embedded, standalone calendar grids.
Date PickerLocalized calendar grid with range selection support.
Observation Date
Exhibition Window

Import

import {
  DatePicker,
  DateRangePicker,
  DateField,
  TimeField,
  Calendar,
  RangeCalendar,
} from "@hashti/react";

Date values are manipulated using @internationalized/date (an industry-standard library included with React Aria):

bun add @internationalized/date
import { parseDate, today, getLocalTimeZone } from "@internationalized/date";

Examples

Single Date Picker

A standard DatePicker with an input field and calendar trigger button:

import { DatePicker } from "@hashti/react";
import { parseDate } from "@internationalized/date";

export function SingleDatePickerDemo() {
  return (
    <div className="max-w-xs">
      <DatePicker
        label="Restoration Milestone Date"
        defaultValue={parseDate("2026-06-15")}
        description="Select the scheduled inspection date."
      />
    </div>
  );
}

Date Range Picker

DateRangePicker manages paired start and end dates with integrated validation, perfect for hotel reservations, travel bookings, and project phases:

import { DateRangePicker } from "@hashti/react";
import { parseDate } from "@internationalized/date";

export function DateRangePickerDemo() {
  return (
    <div className="max-w-sm">
      <DateRangePicker
        label="Residency Duration"
        defaultValue={{
          start: parseDate("2026-09-01"),
          end: parseDate("2026-09-14"),
        }}
        description="Select arrival and departure dates."
      />
    </div>
  );
}

Persian Solar Hijri Calendar Support

Hashti includes architectural support for the Persian Solar Hijri (Jalali) calendar system via @internationalized/date’s PersianCalendar. When paired with an Iranian locale (fa-IR), month names, day orders (Saturday to Friday), and numeral formats correspond directly to Persian standards:

import { DatePicker } from "@hashti/react";
import { today, PersianCalendar, toCalendar } from "@internationalized/date";

export function PersianDatePickerDemo() {
  // Convert current Gregorian date to Persian Solar Hijri (1405 SH)
  const persianToday = toCalendar(today("Asia/Tehran"), new PersianCalendar());

  return (
    <div dir="rtl" className="max-w-xs font-sans">
      <DatePicker
        label="تاریخ آغاز مرمت عمارت"
        defaultValue={persianToday}
        description="تقویم هجری شمسی با پشتیبانی کامل از روزهای هفته و ماه‌ها."
      />
    </div>
  );
}

Date Constraints (Min & Max Boundaries)

Set minValue and maxValue to restrict dates to a valid window. Dates outside this range are visually grayed out and unselectable:

import { DatePicker } from "@hashti/react";
import { today, getLocalTimeZone } from "@internationalized/date";

export function BoundedDateDemo() {
  const current = today(getLocalTimeZone());

  return (
    <div className="max-w-xs">
      <DatePicker
        label="Permit Request Date"
        minValue={current}
        maxValue={current.add({ months: 6 })}
        description="Requests can be submitted up to 6 months in advance."
      />
    </div>
  );
}

Standalone DateField & TimeField

When a calendar popup is unnecessary or when screen space is tight, DateField and TimeField provide tactile segment-by-segment keyboard inputs:

import { DateField, TimeField } from "@hashti/react";
import { parseDate, parseTime } from "@internationalized/date";

export function StandaloneFieldsDemo() {
  return (
    <div className="flex flex-col gap-4 max-w-xs">
      <DateField label="Archival Date" defaultValue={parseDate("1971-10-14")} />

      <TimeField label="Acoustic Measurement Time" defaultValue={parseTime("14:30")} />
    </div>
  );
}

Embedded Calendar Grid

Use <Calendar> directly inline within a dashboard or sidebar panel:

import { useState } from "react";
import { Calendar } from "@hashti/react";
import { today, getLocalTimeZone, type DateValue } from "@internationalized/date";

export function InlineCalendarDemo() {
  const [selectedDate, setSelectedDate] = useState<DateValue>(today(getLocalTimeZone()));

  return (
    <div className="p-4 border rounded-xl max-w-sm">
      <Calendar value={selectedDate} onChange={setSelectedDate} />
      <div className="mt-3 text-xs text-gray-500 text-center">
        Selected: {selectedDate.toString()}
      </div>
    </div>
  );
}

Props Reference

DatePicker Props

PropTypeDefaultDescription
valueDateValue | null—Controlled date value.
defaultValueDateValue—Default date value for uncontrolled usage.
onChange(value: DateValue | null) => void—Handler invoked when the selected date changes.
minValueDateValue—The earliest permissible date.
maxValueDateValue—The latest permissible date.
granularity'day' | 'hour' | 'minute' | 'second''day'Temporal precision level for the segmented field.
labelReactNode—Accessible field label.
descriptionReactNode—Helper text below or above the input.
errorMessageReactNode—Error text rendered when validation fails.
size'sm' | 'md' | 'lg''md'Height and control sizing.
isDisabledbooleanfalseWhether the date picker is disabled.
isReadOnlybooleanfalseWhether the date picker is read-only.
isInvalidbooleanfalseWhether the date picker is in an invalid error state.
isRequiredbooleanfalseWhether a date value is required for form submission.

DateRangePicker Props

PropTypeDefaultDescription
valueDateRange | null—Controlled { start: DateValue, end: DateValue }.
defaultValueDateRange—Default start and end dates.
onChange(range: DateRange | null) => void—Callback fired when the range changes.
minValueDateValue—Earliest selectable date.
maxValueDateValue—Latest selectable date.

Accessibility

The date suite implements the WAI-ARIA Date Picker Pattern with comprehensive keyboard parity:

Segmented Input Navigation

  • → and ← move between date segments (Month, Day, Year).
  • ↑ and ↓ increment and decrement the focused segment.
  • Typing numbers directly sets the segment value (e.g., typing “0” then “5” in the month segment selects May).
  • In RTL locales, segment arrow navigation mirrors automatically.

Calendar Grid Navigation

  • → and ← navigate to the next / previous day.
  • ↑ and ↓ move focus one full week forward or backward.
  • PageUp and PageDown move focus by one month.
  • Alt + PageUp and Alt + PageDown move focus by one year.
  • Home moves to the first day of the month; End moves to the last day of the month.
  • Enter or Space selects the focused date and closes the popover (in single-date mode).
  • Esc closes the calendar popover and returns focus to the trigger button.

Keyboard Interactions

KeyAction
→ / ←Steps between day, month, and year segments.
↑ / ↓Increments or decrements active date segment value.
Space / EnterOpens the calendar popup dialog.
EscCloses calendar popup and restores focus to input.

WAI-ARIA & Data Attributes

AttributeTargetDescription
[data-hovered]Segment, Calendar CellActive on pointer hover.
[data-focused]Segment, Calendar CellActive on focus.
[data-selected]Calendar CellPresent on selected calendar date.