# DatePicker (React Native)

> Dates, ranges and date-times with a Kit-drawn calendar that looks the same on iOS, Android and the web.

GramproKit for React Native · Pickers · Beta · Source: https://kit.gramproindia.com/native/docs/date-picker

> **Beta:** React Native support is in beta. APIs may change or break between prereleases (npm tag `native`).

_Interactive demo:_ [open the live example](https://kit.gramproindia.com/native/docs/date-picker). The example's source:

```tsx
import { useState } from "react";
import { Text } from "react-native";
import { DatePicker, DateRangePicker, DateTimePicker, type DateRange } from "@/component-lib/date-picker";
import { useKitTheme } from "@/component-lib/shared/native";
import { Section } from "./layout"; // Section and Row: page layout for the demo

const addDays = (days: number) => {
  const d = new Date();
  d.setHours(0, 0, 0, 0);
  d.setDate(d.getDate() + days);
  return d;
};
const weekend = (date: Date) => date.getDay() === 0 || date.getDay() === 6;

export function DatePickerDemo() {
  const { tokens } = useKitTheme();
  const [single, setSingle] = useState<Date | null>(null);
  const [range, setRange] = useState<DateRange>({ start: null, end: null });
  const [moment, setMoment] = useState<Date | null>(null);
  const note = { color: tokens.muted, fontSize: tokens.fontSize - 2 };

  return (
    <>
      <Section title="DatePicker · locales">
        <DatePicker
          label="Invoice date (en-IN, week starts Sunday)"
          locale="en-IN"
          value={single}
          onChange={setSingle}
          description="Tap to open the calendar; swipe sideways to change month."
        />
        <Text style={note}>Value: {single ? single.toDateString() : "none"}</Text>
        <DatePicker label="تاريخ الفاتورة (ar-EG, Saturday start)" locale="ar-EG" defaultValue={new Date()} />
        <DatePicker label="Rechnungsdatum (de-DE, Monday start)" locale="de-DE" showWeekNumbers />
      </Section>

      <Section title="DatePicker · limits and errors">
        <DatePicker
          label="Delivery (next 30 days, weekdays only)"
          locale="en-IN"
          min={addDays(1)}
          max={addDays(30)}
          isDateDisabled={weekend}
        />
        <DatePicker label="Date of birth" required error="Enter your date of birth." locale="en-IN" />
        <DatePicker label="Locked" locale="en-IN" defaultValue={new Date()} readOnly />
        <DatePicker label="Disabled" locale="en-IN" disabled />
      </Section>

      <Section title="DateRangePicker">
        <DateRangePicker
          label="Stay"
          locale="en-IN"
          value={range}
          onChange={(next) => setRange(next)}
          min={addDays(0)}
          presets={[
            { label: "This weekend", range: { start: addDays(6 - new Date().getDay()), end: addDays(7 - new Date().getDay()) } },
            { label: "Next 7 days", range: { start: addDays(0), end: addDays(6) } },
            { label: "Next 30 days", range: { start: addDays(0), end: addDays(29) } },
          ]}
        />
        <Text style={note}>
          Range: {range.start?.toDateString() ?? "–"} → {range.end?.toDateString() ?? "–"}
        </Text>
      </Section>

      <Section title="DateTimePicker">
        <DateTimePicker
          label="Meeting (12-hour, 15-minute steps)"
          locale="en-IN"
          hourCycle={12}
          minuteStep={15}
          defaultTime="09:00"
          value={moment}
          onChange={setMoment}
        />
        <Text style={note}>Value: {moment ? moment.toString() : "none"}</Text>
        <DateTimePicker label="Abfahrt (24-hour, seconds)" locale="de-DE" showSeconds />
        <DateTimePicker label="موعد (ar-EG)" locale="ar-EG" />
      </Section>
    </>
  );
}
```

## Install

```bash
npx @grampro/kit@native add DatePicker
```

## Usage

```tsx
import { DatePicker, DateRangePicker, DateTimePicker } from "@/component-lib/date-picker";

<DatePicker label="Due date" locale="en-IN" min={new Date()} onChange={setDue} />
<DateTimePicker label="Reminder" hourCycle={12} minuteStep={15} />
```

## Props

### DatePickerProps

| Prop | Type | Description |
|---|---|---|
| `value` | `DateInput \| null` |   |
| `defaultValue` | `DateInput \| null` |   |
| `onChange` | `(date: Date \| null) => void` | The chosen day as a `Date` at local midnight, or `null` once cleared. |
| `closeOnSelect` | `boolean` | Close the calendar after choosing a date. Default true. |
| `min` | `DateInput \| null` |   |
| `max` | `DateInput \| null` |   |
| `isDateDisabled` | `(date: Date) => boolean` |   |
| `locale` | `string` | BCP-47 tag for month names, digits and the first day of the week. |
| `weekStartsOn` | `number` | 0 = Sunday. Defaults to the locale's first day of the week. |
| `format` | `DateFormat` |   |
| `numberOfMonths` | `number` | Months shown, stacked. Default 1 on native, for every picker. |
| `showWeekNumbers` | `boolean` |   |
| `showToday` | `boolean` | "Today" in the footer. |
| `fixedWeeks` | `boolean` | Always six week rows, so the panel never changes height. Default true. |
| `label` | `ReactNode` |   |
| `description` | `ReactNode` |   |
| `error` | `ReactNode` |   |
| `placeholder` | `string` |   |
| `required` | `boolean` |   |
| `disabled` | `boolean` |   |
| `readOnly` | `boolean` |   |
| `clearable` | `boolean` | Show the clear button. Default true. |
| `size` | `DatePickerSize` | Default `md`. |
| `presentation` | `"auto" \| "sheet" \| "popover"` | Sheet on phones, anchored panel on tablets. Default `auto`. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `DatePickerStyles` |   |
| `localeText` | `Partial<DatePickerLocaleText>` |   |
| `onOpenChange` | `(open: boolean) => void` |   |

### DateRangePickerProps

| Prop | Type | Description |
|---|---|---|
| `value` | `DateRangeInput \| null` |   |
| `defaultValue` | `DateRangeInput \| null` |   |
| `onChange` | `(range: DateRange, complete: boolean) => void` | `complete` is false on the first of the two taps. |
| `presets` | `readonly DatePreset[]` |   |
| `closeOnSelect` | `boolean` | Close once both ends are chosen. Default true. |
| `min` | `DateInput \| null` |   |
| `max` | `DateInput \| null` |   |
| `isDateDisabled` | `(date: Date) => boolean` |   |
| `locale` | `string` | BCP-47 tag for month names, digits and the first day of the week. |
| `weekStartsOn` | `number` | 0 = Sunday. Defaults to the locale's first day of the week. |
| `format` | `DateFormat` |   |
| `numberOfMonths` | `number` | Months shown, stacked. Default 1 on native, for every picker. |
| `showWeekNumbers` | `boolean` |   |
| `showToday` | `boolean` | "Today" in the footer. |
| `fixedWeeks` | `boolean` | Always six week rows, so the panel never changes height. Default true. |
| `label` | `ReactNode` |   |
| `description` | `ReactNode` |   |
| `error` | `ReactNode` |   |
| `placeholder` | `string` |   |
| `required` | `boolean` |   |
| `disabled` | `boolean` |   |
| `readOnly` | `boolean` |   |
| `clearable` | `boolean` | Show the clear button. Default true. |
| `size` | `DatePickerSize` | Default `md`. |
| `presentation` | `"auto" \| "sheet" \| "popover"` | Sheet on phones, anchored panel on tablets. Default `auto`. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `DatePickerStyles` |   |
| `localeText` | `Partial<DatePickerLocaleText>` |   |
| `onOpenChange` | `(open: boolean) => void` |   |

### DateTimePickerProps

| Prop | Type | Description |
|---|---|---|
| `value` | `DateInput \| null` |   |
| `defaultValue` | `DateInput \| null` |   |
| `onChange` | `(date: Date \| null) => void` | The chosen moment as a local `Date`, or `null` once cleared. Fires on Done. |
| `min` | `DateInput \| null` | Earliest moment: earlier days cannot be picked, an earlier time on that day is moved up. |
| `max` | `DateInput \| null` | Latest moment, applied the same way. |
| `hourCycle` | `HourCycle` | 12 shows an AM/PM switch. Defaults to the locale's clock. |
| `showSeconds` | `boolean` | A seconds part as well. Default false. |
| `minuteStep` | `number` | How far the minutes move per step. Default 1. |
| `defaultTime` | `string` | Time used when a day is picked before any time is set, `HH:mm`. Default `00:00`. |
| `showNow` | `boolean` | "Now" in the footer. Default true. |
| `isDateDisabled` | `(date: Date) => boolean` |   |
| `locale` | `string` | BCP-47 tag for month names, digits and the first day of the week. |
| `weekStartsOn` | `number` | 0 = Sunday. Defaults to the locale's first day of the week. |
| `format` | `DateFormat` |   |
| `numberOfMonths` | `number` | Months shown, stacked. Default 1 on native, for every picker. |
| `showWeekNumbers` | `boolean` |   |
| `showToday` | `boolean` | "Today" in the footer. |
| `fixedWeeks` | `boolean` | Always six week rows, so the panel never changes height. Default true. |
| `label` | `ReactNode` |   |
| `description` | `ReactNode` |   |
| `error` | `ReactNode` |   |
| `placeholder` | `string` |   |
| `required` | `boolean` |   |
| `disabled` | `boolean` |   |
| `readOnly` | `boolean` |   |
| `clearable` | `boolean` | Show the clear button. Default true. |
| `size` | `DatePickerSize` | Default `md`. |
| `presentation` | `"auto" \| "sheet" \| "popover"` | Sheet on phones, anchored panel on tablets. Default `auto`. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `DatePickerStyles` |   |
| `localeText` | `Partial<DatePickerLocaleText>` |   |
| `onOpenChange` | `(open: boolean) => void` |   |

## Native and web

- The week starts per locale (Sunday for en-IN, Saturday for ar-EG) even though Hermes has no `Intl.Locale`.
- Tap-only for now: no typed dates. DateTimePicker commits on Done.
- Web version: [DatePicker on the web](https://kit.gramproindia.com/datepicker).
