orn-ui
Organism

DatePicker

Requires <UIProvider> — Getting Started →

Installation

Install just this component (copies the source into your project, no npm dependency)

npx orn-ui add date-picker

Or install the whole package and import it

pnpm add orn-ui
import { DatePicker } from 'orn-ui/date-picker';
Depends on:core (theme + icons)icon-buttonpressable-scale

Usage

  • when to use — An inline calendar. To pick a date from a form, DateField wraps this one in a field.
  • mode — `single` picks one date; `range` picks an interval with two taps.
  • minDate / maxDate — Bound the selection instead of validating afterwards.
  • monthNames / weekdayNames — Localization: the component ships no translations of its own.
  • firstDayOfWeek — `0` Sunday, `1` Monday — a regional decision, not a stylistic one.
Demo clip not recorded yet — see MEDIA.md

Variants

Inline calendar

<DatePicker value={date} onChange={setDate} />

mode="range" — tap start, then end

<View style={{ gap: 8 }}>
  <DatePicker mode="range" range={range} onRangeChange={setRange} />
  <Caption>
    {range?.start
      ? `${range.start.toDateString()} → ${range.end ? range.end.toDateString() : '…'}`
      : 'No range selected'}
  </Caption>
</View>

mode="range" + minDate/maxDate

<DatePicker mode="range" range={range} onRangeChange={setRange} minDate={today} maxDate={inAMonth} />

minDate / maxDate (next 7 days only)

<DatePicker value={ranged} onChange={setRanged} minDate={today} maxDate={inAWeek} />

Week starts on Monday

<DatePicker value={date} onChange={setDate} firstDayOfWeek={1} />

Localized month/weekday names

<DatePicker
  value={date}
  onChange={setDate}
  monthNames={SPANISH_MONTHS}
  weekdayNames={SPANISH_WEEKDAYS}
  firstDayOfWeek={1}
/>
Full demo source
const variants: VariantDef[] = [
  {
    label: 'Inline calendar',
    content: <DatePicker value={date} onChange={setDate} />,
  },
  {
    label: 'mode="range" — tap start, then end',
    content: (
      <View style={{ gap: 8 }}>
        <DatePicker mode="range" range={range} onRangeChange={setRange} />
        <Caption>
          {range?.start
            ? `${range.start.toDateString()} → ${range.end ? range.end.toDateString() : '…'}`
            : 'No range selected'}
        </Caption>
      </View>
    ),
  },
  {
    label: 'mode="range" + minDate/maxDate',
    content: <DatePicker mode="range" range={range} onRangeChange={setRange} minDate={today} maxDate={inAMonth} />,
  },
  {
    label: 'minDate / maxDate (next 7 days only)',
    content: <DatePicker value={ranged} onChange={setRanged} minDate={today} maxDate={inAWeek} />,
  },
  {
    label: 'Week starts on Monday',
    content: <DatePicker value={date} onChange={setDate} firstDayOfWeek={1} />,
  },
  {
    label: 'Localized month/weekday names',
    content: (
      <DatePicker
        value={date}
        onChange={setDate}
        monthNames={SPANISH_MONTHS}
        weekdayNames={SPANISH_WEEKDAYS}
        firstDayOfWeek={1}
      />
    ),
  },
  {
    label: 'DateField — input that opens the calendar',
    content: <DateField label="Due date" value={fieldDate} onChange={setFieldDate} maxDate={inAMonth} />,
  },
  {
    label: 'DateField — custom format',
    content: (
      <DateField
        label="ISO format"
        value={fieldDate}
        onChange={setFieldDate}
        format={(d) => d.toISOString().slice(0, 10)}
      />
    ),
  },
  {
    label: 'DateField — onClear renders the clear button',
    content: (
      <DateField
        label="Due date"
        value={fieldDate}
        onChange={setFieldDate}
        onClear={() => setFieldDate(undefined)}
      />
    ),
  },
  {
    label: 'DateField — mode="range", closes when the range closes',
    content: <DateField label="Stay" mode="range" range={fieldRange} onRangeChange={setFieldRange} />,
  },
  {
    label: 'DateField — required + error',
    content: <DateField label="Due date" required onChange={() => {}} error="Pick a date to continue" />,
  },
  {
    label: 'DateField — disabled',
    content: <DateField label="Locked" value={today} onChange={() => {}} disabled />,
  },
];
return <VariantList variants={variants} />;

Props

Also accepts testID, forwarded to the root node. It exists for end-to-end tests (Maestro drives the app by the accessibility tree) and has no effect on how the component looks or behaves.

NameTypeDefaultDescription
mode?'single' | 'range'single'single' picks one date; 'range' picks an interval with two taps.
value?DateDate picked in mode="single".
onChange?(date: Date) => voidCalled in mode="single".
range?DateRangeRange picked in mode="range".
onRangeChange?(range: DateRange) => voidCalled in mode="range", both when setting the start and when closing the range.
minDate?Date
maxDate?Date
defaultMonth?DatetodayMonth shown on open when there is no `value`.
monthNames?string[]those from `useLabels()`Month names.
weekdayNames?string[]those from `useLabels()`Day initials, index 0 = Sunday.
firstDayOfWeek?0 | 100 = Sunday, 1 = Monday.
onVisibleMonthChange?(month: Date) => voidReports which month became visible when navigating with the arrows.
style?StyleProp<ViewStyle>