Datepicker

A composable date picker with masked input, popup calendar, and support for single, range, and dual-range selection.

Features

  • Input with masked entry
  • Popup calendar
  • Single, range & dual-range modes
  • Controlled or uncontrolled
  • Focus management
  • Headless styling

Installation

npm install @ariaui/datepicker

Examples

Three playgrounds: single date (MDY mask), range with an adjacent time Select, and dual-range (two-pane) stay picker. Calendar styling reuses the same token-backed class maps as the Calendar docs page.

Single date

Uncontrolled single value, MDY mask, and a styled calendar popover.

Preview

No preview output yet.

live.tsxReady

Date range + time

Range mode with ISO-shaped input text; a separate Select demonstrates pairing time with the same row.

Preview

No preview output yet.

live.tsxReady

Dual-range

Hotel-style stay picker: dual-range calendar with shared navigation icons.

Preview

No preview output yet.

live.tsxReady

Framer Motion

Single datepicker content animated with Framer Motion through Content asChild composition.

Preview

No preview output yet.

live.tsxReady

Anatomy

tsx
import * as Datepicker from "@ariaui/datepicker";

export default function Example() {
  return (
    <Datepicker.Root>
      <Datepicker.Label />
      <Datepicker.Input />
      <Datepicker.Trigger />
      <Datepicker.Content>
        <Datepicker.Calendar>
          <Datepicker.CalendarHeader>
            <Datepicker.CalendarPrevious />
            <Datepicker.CalendarMonth />
            <Datepicker.CalendarYear />
            <Datepicker.CalendarNext />
          </Datepicker.CalendarHeader>
          <Datepicker.CalendarBody />
        </Datepicker.Calendar>
      </Datepicker.Content>
    </Datepicker.Root>
  );
}

API Reference

Root

State container. Owns open state, value state, visible month, and input masking configuration.

PropTypeDefault
mode
"single" | "range" | "dual-range""single"
open
boolean
defaultOpen
booleanfalse
onOpenChange
(open: boolean) => void
value
Date | { start?: Date; end?: Date }
defaultValue
Date | { start?: Date; end?: Date }
onValueChange
(value: DatepickerValue) => void
visibleMonth
Date
defaultVisibleMonth
Datenew Date()
onVisibleMonthChange
(month: Date) => void
disabled
booleanfalse
readOnly
booleanfalse
closeOnSelect
booleantrue
inputMask
"mdy" | "iso" | "custom"
parseInput
(text: string, mode: DatepickerMode) => DatepickerValue
formatInput
(value: DatepickerValue, mode: DatepickerMode) => string

Label

Visible and accessible label for the datepicker. Registers the label ID for content labelling.

Trigger

Toggles the picker open and closed. Acts as the fallback positioning reference when input ref is unavailable.

AttributeValues
aria-haspopupdialog
aria-expanded"true" when picker is open
[data-state]"open" | "closed"

Input

Editable input reflecting the formatted date value. Supports masked entry with built-in presets. Commits on Enter and blur.

PropTypeDefault
placeholder
string
AttributeValues
aria-haspopupdialog

Content

Floating picker surface. Portals to the body, positions relative to the input, and manages focus on open/close.

PropTypeDefault
asChild
booleanfalse
AttributeValues
roledialog

Calendar

Embedded calendar bound to the datepicker state. Wraps @ariaui/calendar with shared mode, value, and visible month.

PropTypeDefault
daysInWeek
Record<string, string>
classNames
object

CalendarHeader

Header row for the embedded calendar containing navigation and month/year labels.

CalendarPrevious

Button to navigate to the previous month.

CalendarMonth

Renders the current visible month label.

CalendarMonthSelect

Datepicker-integrated month selector. Closes before the datepicker content when both need to dismiss.

PropTypeDefault
triggerClassName
string
contentClassName
string
optionClassName
string
icon
React.ReactNode
checkIcon
React.ReactNode
contentWrapper
(children: React.ReactNode) => React.ReactNode
AttributeValues
aria-haspopuplistbox

CalendarYear

Renders the current visible year label.

CalendarYearSelect

Datepicker-integrated year selector. Closes before the datepicker content when both need to dismiss.

PropTypeDefault
years
number[]current year ± 10
triggerClassName
string
contentClassName
string
optionClassName
string
icon
React.ReactNode
checkIcon
React.ReactNode
contentWrapper
(children: React.ReactNode) => React.ReactNode
AttributeValues
aria-haspopuplistbox

CalendarNext

Button to navigate to the next month.

CalendarBody

Renders the date grid. In dual-range mode, renders a shared two-pane body.

Keyboard

ShortcutAction
EnterCommit the typed input value. Select the focused date in the calendar.
EscClose the picker and return focus to the trigger.
TabMove focus between input, trigger, and calendar controls.
Move to the same day in the next week (inside the calendar grid).
Move to the same day in the previous week (inside the calendar grid).
Move to the previous day (inside the calendar grid).
Move to the next day (inside the calendar grid).
HomeMove to the first day of the current week.
EndMove to the last day of the current week.

Accessibility

The Datepicker component implements the WAI-ARIA Date Picker Dialog pattern:

  • Trigger exposes aria-haspopup="dialog" and aria-expanded to announce the popup calendar.
  • Input also carries aria-haspopup="dialog" for assistive technology awareness.
  • Content renders as a dialog role and is labelled by the shared Label.
  • Focus moves into the popup when it opens and restores to the trigger when it closes.
  • Escape closes the popup from any focusable element inside it.
  • Date-grid keyboard navigation (arrow keys, Home, End) is delegated to the embedded @ariaui/calendar.
Previous
Context Menu
Next
Dialog