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.SheetstepLabels={{ 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.
| Prop | Type | Required | Description |
|---|---|---|---|
| variant | DateTimePickerVariant | undefined | No | Dresses the **field**. The calendar and the dial take their own. |
| size | DateTimePickerSize | undefined | No | — |
| radius | RadiusKey | undefined | No | — |
| color | string | undefined | No | A raw tint (R7). It reaches the chosen day and the dial's mark. |
| value | Date | undefined | No | The moment chosen. Controlled — leave it out and the picker holds its own. |
| defaultValue | Date | undefined | No | — |
| onValueChange | ((value: Date) => void) | undefined | No | — |
| isOpen | boolean | undefined | No | Whether the sheet is open. Present means controlled. |
| defaultOpen | boolean | undefined | No | — |
| onOpenChange | ((isOpen: boolean) => void) | undefined | No | — |
| step | DateTimePickerStep | undefined | No | Which half is on screen. Present means controlled. |
| defaultStep | DateTimePickerStep | undefined | No | — |
| onStepChange | ((step: DateTimePickerStep) => void) | undefined | No | — |
| hourCycle | HourCycle | undefined | No | Twelve hours and a period, or twenty-four. Unset, it is `locale`'s. |
| minuteStep | number | undefined | No | — |
| minValue | Date | undefined | No | — |
| maxValue | Date | undefined | No | — |
| locale | string | undefined | No | Names the months, the weekdays and the field's text. |
| formatOptions | DateTimeFormatOptions | undefined | No | How the field reads the moment. |
| closeOnSelect | boolean | undefined | No | Whether choosing the minutes closes the sheet. |
| isDisabled | boolean | undefined | No | — |
| isInvalid | boolean | undefined | No | — |
| children | ReactNode | No | — |
Slots
DateTimePickerCalendarProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| previousLabel | string | undefined | No | — |
| nextLabel | string | undefined | No | — |
DateTimePickerClockProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
DateTimePickerIndicatorProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
DateTimePickerSheetProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| stepLabels | Record<DateTimePickerStep, string> | undefined | No | What the two steps are called. The words are a language's, so they are given. |
| previousLabel | string | undefined | No | The calendar's two arrows, as on the `Calendar` itself. |
| nextLabel | string | undefined | No | — |
DateTimePickerTextProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | No | — |
DateTimePickerTriggerProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| asChild | boolean | undefined | No | Merge 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. |
| children | ReactNode | No | — |
| style | StyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>) | No | R9 — `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.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | No | — |
| placeholder | string | undefined | No | What 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.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | No | — |
Variants, sizes and colour
Accessibility
Migration from legacy
Implementation notes
It owns nothing at all
| the part | what it actually is |
|---|---|
| the field | a Select's trigger |
| the two steps | a Tabs |
| the month | a Calendar |
| the dial | a TimePicker |
| the mark | TimePicker.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.DatePickerandTimePicker— either half on its own.