Pick a Date, the Native Way, with React Native DateTimePicker
Picking a date or a time is one of those tasks that feels like it should take five minutes and somehow eats an afternoon. Every mobile OS already ships a polished, accessibility-tested, locale-aware picker, the iOS wheel and inline calendar, the Android calendar and clock dialogs, and your users already trust those controls because they see them everywhere else on their phone. React Native DateTimePicker (@react-native-community/datetimepicker) is the thin native bridge that hands those exact widgets to your React Native app instead of making you rebuild them in JavaScript.
This is not a lookalike. On iOS you get the real UIDatePicker. On Android you get the native DatePickerDialog, TimePickerDialog, and the Material 3 pickers. That means correct localization, time zones, dark mode, and accessibility come for free. With roughly 1.8 million weekly downloads, bundled into Expo Go, and essentially zero runtime dependencies, it is the de facto standard, and several higher-level picker libraries are built directly on top of it.
What Makes It Worth Reaching For
- Truly native UI on every platform. iOS, Android, Windows, and Expo all get their own genuine OS controls rather than a styled JavaScript approximation.
- Multiple modes.
date(the default),time, plusdatetimeandcountdownwhich are iOS-only. - Per-platform display variants. iOS offers
spinner,compact, andinline; Android offersspinner,calendar, andclock. - Range constraints.
minimumDateandmaximumDatekeep selections inside a window (with one Android caveat we will cover below). - Rich localization. Force a 24-hour clock with
is24Hour, set an IANAtimeZoneNamelike"Europe/Prague", and lean on the platform's own locale handling. - Material 3 support on Android. Opt in with
design: "material"to unlock titles, fullscreen mode, and keyboard input. - Almost dependency-free. The only runtime dependency is
invariant, which keeps your bundle lean and your install graph boring (in the best way).
Getting It Into Your Project
Install it like any other native module:
npm install @react-native-community/datetimepicker
Or with yarn:
yarn add @react-native-community/datetimepicker
If you are on Expo, let the CLI pick a version that matches your SDK:
npx expo install @react-native-community/datetimepicker
The picker is bundled into Expo Go, so it works in a managed Expo project without a custom dev client. Just be aware that Expo Go may lag the very latest release; for cutting-edge features use a Dev Client or prebuild.
Showing a Picker on iOS
On iOS the picker is a regular React component that lives in your view tree. You conditionally render it and drive it with state. The most common pattern is a button that flips a show flag, a mode to choose between date and time, and a controlled value.
import { useState } from 'react';
import { Button, SafeAreaView, Text } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
type PickerMode = 'date' | 'time';
export const App = () => {
const [date, setDate] = useState(new Date());
const [mode, setMode] = useState<PickerMode>('date');
const [show, setShow] = useState(false);
const showMode = (currentMode: PickerMode) => {
setMode(currentMode);
setShow(true);
};
return (
<SafeAreaView>
<Button onPress={() => showMode('date')} title="Show date picker" />
<Button onPress={() => showMode('time')} title="Show time picker" />
<Text>Selected: {date.toLocaleString()}</Text>
{show && (
<DateTimePicker
value={date}
mode={mode}
is24Hour
onValueChange={(_event, selectedDate) => {
if (selectedDate) setDate(selectedDate);
}}
onDismiss={() => setShow(false)}
/>
)}
</SafeAreaView>
);
};
Because the picker renders inline as part of your layout, a true modal "popup" feel is something you build yourself, or delegate to a wrapper library. The component mounts when show is true and unmounts when you set it back to false.
Showing a Picker on Android
Here is the single biggest thing that trips people up: Android does not work the same way. Its native pickers are dialogs, so there is nothing to render inline. The idiomatic approach is imperative, you call a static method to open the dialog.
import { DateTimePickerAndroid } from '@react-native-community/datetimepicker';
const openAndroidPicker = (currentMode: 'date' | 'time', current: Date, onPick: (d: Date) => void) => {
DateTimePickerAndroid.open({
value: current,
mode: currentMode,
is24Hour: true,
onValueChange: (_event, selectedDate) => {
if (selectedDate) onPick(selectedDate);
},
});
};
// Need to close it from code? Call:
// DateTimePickerAndroid.dismiss('date');
The two platforms genuinely have asymmetric APIs: a declarative component on iOS, an imperative method on Android. A naive <DateTimePicker /> works beautifully on iOS but feels awkward on Android, and vice versa. The clean fix is to branch on Platform.OS and expose one helper that does the right thing on each side.
import { Platform } from 'react-native';
const showPicker = (mode: 'date' | 'time', current: Date, onPick: (d: Date) => void) => {
if (Platform.OS === 'android') {
openAndroidPicker(mode, current, onPick);
} else {
// On iOS, flip your render flag instead.
setIosVisible(true);
}
};
The New Event Listeners
For years there was a single callback, onChange, which fires for every kind of event and forces you to inspect event.type to figure out what happened.
const onChange = (event, selectedDate?: Date) => {
const { type } = event;
if (type === 'set' && selectedDate) {
setDate(selectedDate);
}
// type can also be 'dismissed' or 'neutralButtonPressed' on Android.
};
As of v9.1.0 (March 2026) the library introduced more granular listeners and deprecated onChange in favor of three focused callbacks:
onValueChange(event, date)fires when the user actually picks a value.onDismiss()fires when the picker closes without a selection.onNeutralButtonPress()fires for the Android neutral button.
The old onChange still works, so existing code keeps running untouched, but new code should prefer the split listeners. If you provide both, the specific listeners take precedence for their respective events. The result is a tidier handler with no branching on a stringy type field, which is exactly what you saw in the iOS example above.
Theming, Time Zones, and Material 3
The picker exposes a generous set of styling and formatting props, and many are platform-specific. On iOS you can tune the spinner with textColor, set an accentColor, force light or dark with themeVariant, and constrain time selection with minuteInterval (valid values include 5, 10, 15, and 30). On both platforms you can pin the wall clock to a specific zone with timeZoneName using IANA identifiers.
<DateTimePicker
value={date}
mode="datetime"
display="inline"
themeVariant="dark"
accentColor="#FF6B35"
minuteInterval={15}
timeZoneName="Europe/Prague"
onValueChange={(_event, selectedDate) => selectedDate && setDate(selectedDate)}
/>
On Android, opting into the Material 3 pickers unlocks a more modern look and several extra props. Set design: "material" to gain access to title, fullscreen, initialInputMode for keyboard entry, and startOnYearSelection. This requires your app theme to inherit from Theme.Material3.DayNight.NoActionBar, so it is a small native configuration step rather than a pure JavaScript change.
DateTimePickerAndroid.open({
value: date,
mode: 'date',
design: 'material',
title: 'Pick your start date',
initialInputMode: 'keyboard',
onValueChange: (_event, selectedDate) => selectedDate && setDate(selectedDate),
});
A few platform gotchas are worth keeping in your back pocket. The Android time picker ignores minimumDate and maximumDate, those constraints only apply to date mode there. The datetime and countdown modes are iOS-only. And in iOS dark mode, the spinner text needs a visible background, so reach for themeVariant or the Appearance API to avoid invisible text.
When to Pair It With a Wrapper
If the iOS-versus-Android asymmetry bothers you, you are not stuck with hand-rolling it. The popular react-native-modal-datetime-picker is built directly on top of this library and wraps it in a single declarative modal API (isVisible, onConfirm, onCancel) that behaves the same on both platforms. Because that wrapper delegates to the community picker under the hood, learning this library pays off no matter which route you take. If instead you want a uniform branded spinner that looks identical across platforms, react-native-date-picker is a standalone alternative, but you trade away each platform's distinct native widget to get that consistency.
Wrapping Up
React Native DateTimePicker earns its spot as the ecosystem standard by doing one thing extremely well: it gets out of your way and lets the operating system render the date and time controls users already know. You get genuine native look and feel, correct localization and time zones, accessibility, and dark mode without styling a single pixel yourself. The one real cost, the declarative-iOS versus imperative-Android split, is well understood and easy to tame with a Platform.OS branch or a thin wrapper. With the new onValueChange, onDismiss, and onNeutralButtonPress listeners in v9.1.0, the developer experience is cleaner than ever. Whether you use it directly or as the foundation under a higher-level library, it is the dependable choice for letting people pick a moment in time.