Every React Native app I've worked on ended up with the same pile of packages:
-
@react-native-community/datetimepickerfor dates and times -
react-native-calendarsbecause the date picker can't do ranges - a dropdown library, because the native picker can't search
- a country picker, then a phone input on top of it
- an emoji keyboard for the chat screen
- a bottom sheet to put half of these in
Six APIs, six looks, some of them native modules that need a rebuild, and most of them broken or missing on the web.
So I built React Native Pickers: one package with all of them, written in plain JavaScript on React Native's own APIs. No native code, no dependencies.
What's in it
- Wheels: the 3D iOS wheel, with looping, disabled rows and tap-to-type
- Dates: a calendar (single day, range, multiple days, several ranges) or day / month / year wheels; a month picker; a week strip
- Time: wheels, the Material clock dial, or columns to click; durations
- Date and time together
- Select: search, multi-select with chips, groups, icons and server search
- Country: about 250 countries with flag emoji, dialing codes and names in the user's language
- Phone number: a country code button, formatting as you type, an E.164 value
- Emoji: 1,923 emojis with search, skin tones and recently used
- Color: iOS's grid / spectrum / sliders, Google's swatch circles, or the browser's spectrum
- Segmented control and chips
- Bottom sheets and form fields to put any of them in
What using it looks like
import { useState } from 'react';
import { View } from 'react-native';
import { DatePickerField, SelectPicker, TimePickerField } from '@elik56a/react-native-pickers';
import type { DateRange } from '@elik56a/react-native-pickers';
const ROOMS = [
{ label: 'Single', value: 'single' },
{ label: 'Double', value: 'double' },
{ label: 'Suite', value: 'suite' },
];
export default function Booking() {
const [stay, setStay] = useState<DateRange>({ start: null, end: null });
const [arrival, setArrival] = useState<Date | undefined>();
const [room, setRoom] = useState<string | null>(null);
return (
<View style={{ gap: 16, padding: 16 }}>
<DatePickerField label="Stay" mode="range" value={stay} onConfirm={setStay} minDate={new Date()} />
<TimePickerField label="Arrival" value={arrival} onConfirm={setArrival} minuteInterval={15} />
<SelectPicker label="Room" options={ROOMS} value={room} onChange={setRoom} />
</View>
);
}
Each field opens its picker in a bottom sheet on a phone and a dropdown in the browser, and shows the chosen value formatted for the user's locale. Every component is controlled the same way: value and onChange (or onConfirm for the sheets), and onChange only fires when the user changes something.
It looks native on each platform
This is the part I cared about most. By default each picker takes the design of the platform it runs on:
- iOS: wheels, a tinted selected day, Cancel and Done in the sheet header
- Android: Material Design, with the clock dial, outlined fields with floating labels, and OK at the bottom
- Web: a compact calendar, time columns to click, dropdowns, and a focus ring
If your app has its own look and you want the same pickers everywhere, it's one line:
<PickersProvider design="ios">
<App />
</PickersProvider>
Dark mode follows the system, and every color, radius and font comes from theme tokens you can override. Every visual part also has a style slot, and render props let you replace a day cell, an option row or the whole field.
Why zero native code matters
Everything is built on React Native's core APIs: Animated with the native driver, PanResponder, FlatList and Modal. No Reanimated, no Gesture Handler, no SVG. That means:
- it works in Expo Go, with no development build and no config plugin
- it ships in over-the-air updates, because there's nothing native to rebuild
- it works on React Native Web, which is where most picker libraries fall short
- it doesn't break when your React Native version changes
Things I didn't want to install separately
A few details that usually mean another package:
-
Prices and dots on calendar days.
markedDatestakes a label and up to three colored dots per day, so a booking calendar can show$129under each night. -
Server search. Give
SelectPickeraloadOptions(query)that returns a promise; it debounces, shows a loader and ignores stale answers. -
Phone numbers without libphonenumber.
PhoneFieldgroups digits the way about 50 countries write them, drops the leading 0 people type at home, and reads the country from a pasted+44…number. The value is always E.164, like+447911123456. - Accessibility. Wheels are adjustable for VoiceOver and TalkBack, days announce their full date, and on the web you can use every picker from the keyboard.
Coming from another library?
There's a prop-by-prop migration guide for 12 libraries: @react-native-community/datetimepicker, react-native-date-picker, react-native-modal-datetime-picker, react-native-calendars, @react-native-picker/picker, react-native-picker-select, react-native-dropdown-picker, react-native-element-dropdown, react-native-country-picker-modal, react-native-phone-number-input, rn-emoji-keyboard and @react-native-segmented-control/segmented-control. Most of them come down to renaming a few props.
Try it
npx expo install @elik56a/react-native-pickers
- Docs with live, editable examples: https://react-native-pickers.dev/
- Showcase of real screens (booking, flights, alarm, chat, checkout), switchable between iOS, Android and web: https://react-native-pickers.dev/showcase
- GitHub: https://github.com/elik56a/react-native-pickers
It's MIT licensed and I'm working on it actively. I'd really like to hear what's missing, what breaks in your app, and what you'd need before using it in production. Comments here or issues on GitHub both work, and a star helps other people find it.

Top comments (0)