BetaForms

DateTimePicker

A field that opens a month, and then a clock.

Overview

A field that opens a month, and then a clock.

First example

<DateTimePicker value={moment} onValueChange={setMoment}>
<DateTimePicker.Trigger>
<DateTimePicker.Value placeholder="Choisir un moment" />
<DateTimePicker.Indicator />
</DateTimePicker.Trigger>
<DateTimePicker.Sheet
stepLabels={{ date: 'Date', time: 'Heure' }}
previousLabel="Mois précédent"
nextLabel="Mois suivant"
/>
</DateTimePicker>

Anatomy

<DateTimePicker>
  <DateTimePicker.Calendar />
  <DateTimePicker.Clock />
  <DateTimePicker.Indicator />
  <DateTimePicker.Sheet />
  <DateTimePicker.Text />
  <DateTimePicker.Trigger />
  <DateTimePicker.Value />
  <DateTimePicker.View />
</DateTimePicker>

Usage

<DateTimePicker value={moment} onValueChange={setMoment}>
  <DateTimePicker.Trigger>
    <DateTimePicker.Value placeholder="Choisir un moment" />
    <DateTimePicker.Indicator />
  </DateTimePicker.Trigger>
  <DateTimePicker.Sheet
    stepLabels={{ date: 'Date', time: 'Heure' }}
    previousLabel="Mois précédent"
    nextLabel="Mois suivant"
  />
</DateTimePicker>

Root props

DateTimePickerProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
variantDateTimePickerVariant | undefinedNoDresses the **field**. The calendar and the dial take their own.
sizeDateTimePickerSize | undefinedNo
radiusRadiusKey | undefinedNo
colorstring | undefinedNoA raw tint (R7). It reaches the chosen day and the dial's mark.
valueDate | undefinedNoThe moment chosen. Controlled — leave it out and the picker holds its own.
defaultValueDate | undefinedNo
onValueChange((value: Date) => void) | undefinedNo
isOpenboolean | undefinedNoWhether the sheet is open. Present means controlled.
defaultOpenboolean | undefinedNo
onOpenChange((isOpen: boolean) => void) | undefinedNo
stepDateTimePickerStep | undefinedNoWhich half is on screen. Present means controlled.
defaultStepDateTimePickerStep | undefinedNo
onStepChange((step: DateTimePickerStep) => void) | undefinedNo
hourCycleHourCycle | undefinedNoTwelve hours and a period, or twenty-four. Unset, it is `locale`'s.
minuteStepnumber | undefinedNo
minValueDate | undefinedNo
maxValueDate | undefinedNo
localestring | undefinedNoNames the months, the weekdays and the field's text.
formatOptionsDateTimeFormatOptions | undefinedNoHow the field reads the moment.
closeOnSelectboolean | undefinedNoWhether choosing the minutes closes the sheet.
isDisabledboolean | undefinedNo
isInvalidboolean | undefinedNo
childrenReactNodeNo

Slots

DateTimePickerCalendarProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
previousLabelstring | undefinedNo
nextLabelstring | undefinedNo

DateTimePickerClockProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

This slot adds nothing to the props of its React Native node.

DateTimePickerIndicatorProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

This slot adds nothing to the props of its React Native node.

DateTimePickerSheetProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
stepLabelsRecord<DateTimePickerStep, string> | undefinedNoWhat the two steps are called. The words are a language's, so they are given.
previousLabelstring | undefinedNoThe calendar's two arrows, as on the `Calendar` itself.
nextLabelstring | undefinedNo

DateTimePickerTextProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
childrenReactNodeNo

DateTimePickerTriggerProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
asChildboolean | undefinedNoMerge into the single child instead of rendering a pressable (R12) — **keeping the feedback**. Swapping this component out for a bare `Slot` would silently drop the touch feedback of every `asChild` control.
childrenReactNodeNo
styleStyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>)NoR9 — `Pressable`'s function form as much as an object or an array.

DateTimePickerValueProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
childrenReactNodeNo
placeholderstring | undefinedNoWhat the field says with no moment chosen.

DateTimePickerViewProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
childrenReactNodeNo

Variants, sizes and colour

This component adds no visual axis of its own. The values it does take are in the generated types above and in the live demo.

Accessibility

The source defines no extra rule. Keep the React Native labels, roles, states and focus order your case needs, then check the result with VoiceOver and TalkBack.

Migration from legacy

This component declares no rule of its own. The migration guide covers variants, colours and slots.

Implementation notes

It owns nothing at all

the partwhat it actually is
the fielda Select's trigger
the two stepsa Tabs
the montha Calendar
the diala TimePicker
the markTimePicker.Indicator

Four components rendered as themselves rather than four tables restated. It has no recipe of its own — the only style it touches is the field's, and that one belongs to the Select.

That is also why TimePicker.Indicator reads IconContext rather than its own picker's context: a glyph another field can render is one glyph to keep right, not two.

Two steps rather than two fields

A moment is one value, so it is one control. A calendar and a clock will not fit on a phone at the same time, which is why the two take turns.

Choosing a day moves to the clock — the TimePicker's hours handing over to its minutes, one level up — and choosing the minutes closes the sheet. The common path is one gesture.

The steps are a tab bar and not a stepper, because either half can be changed at any time: a reader who set the day, then the time, then wants the day again presses "date" rather than starting over.

Each tab reads the half it stands for once there is one — the date under "date", the time under "time" — so the sheet says what has been decided without a header of its own.

The sheet reopens on the date, always: one that reopened on the clock would hide the month from a reader who came to change the day.

Each half keeps the other

A day chosen after a time keeps the time. A time chosen after a day keeps the day. The value is one moment being narrowed, not two values being collected.

With nothing chosen yet, the first day lands at midnight — which is what the dial shows when it opens.

The pieces are composable

DateTimePicker.Sheet with no children assembles Steps, Calendar and Clock. Written out, the whole thing goes on a page with no sheet at all, which is also how the demo screen makes both steps visible without opening anything:

<DateTimePicker
  value={moment}
  onValueChange={setMoment}
  step={step}
  onStepChange={setStep}
>
  <DateTimePicker.Steps labels={labels} />
  {step === 'date' ? <DateTimePicker.Calendar /> : <DateTimePicker.Clock />}
</DateTimePicker>

DateTimePicker.Clock renders a real TimePicker with closeOnSelect={false}: the minutes close the sheet the trigger opened, and that inner picker has no sheet of its own.

See also

  • DateTimeField — a moment typed rather than chosen.
  • DatePicker and TimePicker — either half on its own.