# Date Picker

> Dates are typed when people know them (a birthday, a document), picked from a calendar when they browse for a day, ranges come with presets, and time has its own input. In Arabic the fields and the grid mirror, and the week starts from the locale.

Source: https://ritla.app/ui/date-picker

## Installation

Installing from the registry is coming soon. Until then, these are the commands you will run.

```bash
npx ritla add date-picker
```

With the shadcn CLI instead:

```bash
npx shadcn@latest add @ritla/date-picker
```

Dependencies: `@base-ui/react`, `@phosphor-icons/react`, `react-day-picker`

## Usage

```tsx
import { DateInput } from "@/components/ui/date-picker";

const [date, setDate] = useState<Date | null>(null);

<DateInput label="Transfer date" value={date} onValueChange={setDate} />
```

## Examples

### A date people know

A date of birth is typed, not browsed: `picker={false}` removes the calendar button, and `showAge` shows the age so people can check the year. The segments follow the region's order (day first in Arabic) and accept Arabic-Indic digits when typed.

Live preview: https://ritla.app/_kanz/preview/ltr/date-picker-birth

### Time

`TimeInput`: hour and minute, then AM / PM, and the time zone when it matters. The clock keeps its order in Arabic: hour, then minute, from the left.

Live preview: https://ritla.app/_kanz/preview/ltr/date-picker-time

### A range with presets

`DateRangePicker`: the presets people actually use, two months on desktop and one on phones, and the chosen range written out in the field ("March 1 – 15, 2026").

Live preview: https://ritla.app/_kanz/preview/ltr/date-picker-range

### Date picker menu

`DatePickerMenu` on its own: the month and year buttons open their lists, then Cancel and Apply. Put it in a Popover, a Dialog or a Drawer as the screen needs.

Live preview: https://ritla.app/_kanz/preview/ltr/date-picker-menu

## API reference

### `DateInput`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value / onValueChange` | `Date \| null / (value: Date \| null) => void` | None | A complete date, or `null` while it is empty or not real (31 February is not a date). |
| `label / required / helperText / error` | `ReactNode / boolean` | None | As in Input. Say the format in the helper text when it could be misread. |
| `showAge` | `boolean` | `false` | Figma's age badge, for a date of birth. |
| `picker` | `boolean` | `true` | The calendar button that opens the Date picker menu. |
| `min / max` | `Date` | None | The first and last dates the menu offers. |
| `order` | `("day" \| "month" \| "year")[]` | None | Default: the region's order. Day first in Arabic, month first in en-US. |
| `disabled / readOnly` | `boolean` | None | Figma's State. |

### `TimeInput`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value / onValueChange` | `{ hours, minutes } \| null` | None | Hours from 0 to 23. |
| `hourCycle` | `"h12" \| "h23"` | `"h12"` | 12 hours with AM / PM, or 24 hours. |
| `timeZone` | `ReactNode` | None | The time zone at the end of the field when it matters ("UTC +03:00"). |

### `DatePicker / DatePickerMenu`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `trigger (DatePicker)` | `ReactElement` | None | The control that opens the menu in a Popover. |
| `value / onApply / onCancel (Menu)` | `Date / (value: Date) => void / () => void` | None | The day the menu opens on, and Apply and Cancel. |
| `fromYear / toYear (Menu)` | `number` | None | The year list's range. |

### `DateRangePicker / DateRangeMenu`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value / onValueChange` | `DateRange` | None | The range `{ from, to }`. |
| `presets` | `{ label, range }[]` | None | Default: Figma's eight. Today, Yesterday, This week, Last week, This month, Last month, This year, Last year. |
| `numberOfMonths (Menu)` | `1 \| 2` | `2` | Two months on desktop, one on phones. |

## Accessibility

Keyboard (keys as in left-to-right; arrows swap in right-to-left):

- `Tab`: From one segment to the next, then the calendar button.
- `ArrowUp` + `ArrowDown`: Steps the segment up or down; on AM / PM, switches it.
- `Backspace`: In an empty segment, goes back to the previous one.
- `Enter`: On the calendar button, opens the menu; in the grid, chooses the day (see Calendar).
- `Escape`: Closes the menu without a change.

ARIA:

- The field is a group named by its label, and each segment a numeric field with its name ("Day", "Month", "Year").
- Typing is always the accessible way in; never make the calendar the only one.
- AM / PM is a spinbutton that reads its value. The age badge reads "Age 34".
- The calendar, month and year buttons are named in the page language, and the month and year lists are `listbox`es.

## Arabic and RTL notes

Mirrors:

- The date segments: the day on the right, then the month, then the year on the left; the calendar button and the age badge on the left.
- The presets at the menu's inline start (the right), and Apply at the end of the buttons.

Does not mirror:

- The clock: hour, then minute, from the left, as on a clock.
- Each segment's digits, and the UTC time zone.

Numerals: Segments, the grid and the age badge follow `numerals`, and typing accepts both systems.

Arabic typography: Segments are `label-16`, the month and year buttons `body-16` Semibold.

Mixed-direction text: Never mix Hijri and Gregorian in one field: Hijri has its own picker.
