React Native ships no dropdown or select in its core component list. You either build one from a Pressable trigger, a Modal and a FlatList of options, or install the community package @react-native-picker/picker, which wraps the native picker on Android and iOS. Build your own when you need search, custom rows or one look on every platform.
| Approach | Install | Best for |
|---|---|---|
| Pressable + Modal + FlatList | Nothing, all core | Custom styling, search, long lists |
| @react-native-picker/picker | npm install @react-native-picker/picker | The platform's own picker look |
| ActionSheetIOS | Nothing, iOS only | A short list of actions on iPhone |
Updated
The preview below runs the same logic as the React Native code further down, drawn with web elements so you can try it here: open the list, filter it, pick a row and close it with Escape. Then copy the component and swap the web tags for View, Text, Pressable, Modal and FlatList.
Web stand-in for the React Native component: the same open, filter and pick logic, drawn with HTML so it runs here.
Nothing selected yet.
| Component | Prop | What it does |
|---|---|---|
| Modal | visible | Shows or hides the list (default true) |
| Modal | transparent | Renders over a see-through background instead of filling the screen |
| Modal | animationType | "none" (default), "slide" or "fade" |
| Modal | onRequestClose | Called for the Android back button; required on Android |
| FlatList | data / renderItem | The options array and the function that draws each row |
| FlatList | keyExtractor | Returns a unique key per option |
| FlatList | keyboardShouldPersistTaps | "never" (default), "always" or "handled" |
| Picker | mode | Android only: "dialog" (default) or "dropdown" |
No dependencies. The parent owns the value; the component only reports the choice through onChange.
import { useState } from "react";
import { FlatList, Modal, Pressable, StyleSheet, Text, View } from "react-native";
export function Dropdown({ label, options, value, onChange }) {
const [open, setOpen] = useState(false);
return (
<View>
<Pressable
accessibilityRole="button"
accessibilityLabel={`${label}: ${value ?? "none"}`}
onPress={() => setOpen(true)}
style={s.trigger}
>
<Text>{value ?? "Choose..."}</Text>
</Pressable>
<Modal visible={open} transparent animationType="fade" onRequestClose={() => setOpen(false)}>
<Pressable style={s.backdrop} onPress={() => setOpen(false)}>
<View style={s.sheet}>
<FlatList
data={options}
keyExtractor={(item) => item}
keyboardShouldPersistTaps="handled"
renderItem={({ item }) => (
<Pressable
accessibilityRole="button"
accessibilityState={{ selected: item === value }}
onPress={() => { onChange(item); setOpen(false); }}
style={({ pressed }) => [s.row, pressed && s.pressed]}
>
<Text style={item === value ? s.bold : null}>{item}</Text>
</Pressable>
)}
/>
</View>
</Pressable>
</Modal>
</View>
);
}
const s = StyleSheet.create({
trigger: { borderWidth: 1, borderColor: "#cbd5e1", borderRadius: 8, padding: 12 },
backdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.4)", justifyContent: "center", padding: 24 },
sheet: { backgroundColor: "#fff", borderRadius: 12, maxHeight: "70%" },
row: { padding: 14 },
pressed: { backgroundColor: "#f1f5f9" },
bold: { fontWeight: "700" },
});Install with npm install @react-native-picker/picker. onValueChange receives the item value and its position.
import { useState } from "react";
import { Picker } from "@react-native-picker/picker";
export function CityPicker() {
const [city, setCity] = useState("toronto");
return (
<Picker
selectedValue={city}
onValueChange={(value, index) => setCity(value)}
mode="dropdown" // Android only
>
<Picker.Item label="Toronto" value="toronto" />
<Picker.Item label="Vancouver" value="vancouver" />
<Picker.Item label="Montreal" value="montreal" />
</Picker>
);
}
The community Picker is the quickest route and looks native on each platform, which also means it looks different on Android and iOS. If your design calls for the same list everywhere, a filter box, icons, or two lines per row, the Modal version gives you full control in about fifty lines.
FlatList only renders the rows near the screen, so a list of countries or time zones stays fast inside the Modal. A plain map over a long array inside a ScrollView renders everything at once.
Screen readers cannot guess that your Pressable opens a list. Give it accessibilityRole="button", a label that names the field and its current value, and set accessibilityState with selected: true on the chosen row inside the list.
Closing the list should return the user to the trigger. Keep the Modal's onRequestClose wired up and add a visible close control for people who do not use the back gesture.
No. The core components page lists Button and Switch under user interface controls, and nothing for selects. For a ready-made native select, install the community package @react-native-picker/picker.
Set mode="dropdown" on the Picker. That prop is Android only; the default there is "dialog", which opens a modal list. On iOS the component shows the native wheel instead.
A scrolling list defaults keyboardShouldPersistTaps to "never", so the first tap outside the focused input dismisses the keyboard and the row never receives it. Set the prop to "handled" on the FlatList.
Yes, with the custom build. Keep a query string in state, put a TextInput at the top of the Modal, and pass the filtered array to the FlatList data prop.
Related: React vs React Native, React Native forms, React Native radio buttons, React Native TextInput props, React hooks cheat sheet.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.