What is a dropdown in React Native?
A dropdown (or select) lets the user pick one value from a list that appears on tap. Unlike the web’s <select>, React Native ships no dropdown element — so you either build one from core components or install one. For most apps the dependency-free Modal approach below is the safest: it works identically on iOS and Android, floats above other content, and adds nothing to your bundle.
Basic example (no dependencies)
A trigger that opens a Modal with a FlatList of options. This is the pattern to reach for first:
import { useState } from 'react';
import { Modal, Pressable, Text, View, FlatList } from 'react-native';
function Dropdown({ options, value, onChange, placeholder = 'Select…' }) {
const [open, setOpen] = useState(false);
return (
<View>
{/* the trigger */}
<Pressable
onPress={() => setOpen(true)}
style={{
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: 8,
padding: 12,
}}
>
<Text style={{ fontSize: 16, color: value ? '#111827' : '#9ca3af' }}>
{value ?? placeholder}
</Text>
</Pressable>
{/* the menu — a Modal so it floats above everything */}
<Modal visible={open} transparent animationType="fade" onRequestClose={() => setOpen(false)}>
<Pressable style={{ flex: 1, backgroundColor: '#00000055' }} onPress={() => setOpen(false)}>
<View style={{ margin: 24, marginTop: 120, backgroundColor: '#fff', borderRadius: 12 }}>
<FlatList
data={options}
keyExtractor={(item) => item}
renderItem={({ item }) => (
<Pressable
onPress={() => { onChange(item); setOpen(false); }}
style={{ padding: 14, borderBottomWidth: 1, borderBottomColor: '#f3f4f6' }}
>
<Text style={{ fontSize: 16 }}>{item}</Text>
</Pressable>
)}
/>
</View>
</Pressable>
</Modal>
</View>
);
}Searchable dropdown
Once the list gets past ~10 items, add a search field. Filter with a memoized list so it stays fast:
import { useMemo, useState } from 'react';
import { Modal, Pressable, Text, TextInput, View, FlatList } from 'react-native';
function SearchableDropdown({ options, value, onChange }) {
const [open, setOpen] = useState(false);
const [query, setQuery] = useState('');
const filtered = useMemo(
() => options.filter((o) => o.toLowerCase().includes(query.toLowerCase())),
[options, query],
);
return (
<View>
<Pressable onPress={() => setOpen(true)} style={{ borderWidth: 1, borderColor: '#e5e7eb', borderRadius: 8, padding: 12 }}>
<Text style={{ fontSize: 16 }}>{value ?? 'Select…'}</Text>
</Pressable>
<Modal visible={open} transparent animationType="fade" onRequestClose={() => setOpen(false)}>
<View style={{ flex: 1, backgroundColor: '#00000055', paddingTop: 100, paddingHorizontal: 24 }}>
<View style={{ backgroundColor: '#fff', borderRadius: 12, overflow: 'hidden' }}>
<TextInput
autoFocus
value={query}
onChangeText={setQuery}
placeholder="Search…"
style={{ padding: 14, borderBottomWidth: 1, borderBottomColor: '#e5e7eb', fontSize: 16 }}
/>
<FlatList
data={filtered}
keyExtractor={(item) => item}
keyboardShouldPersistTaps="handled"
style={{ maxHeight: 260 }}
renderItem={({ item }) => (
<Pressable onPress={() => { onChange(item); setOpen(false); setQuery(''); }} style={{ padding: 14 }}>
<Text style={{ fontSize: 16 }}>{item}</Text>
</Pressable>
)}
/>
</View>
</View>
</Modal>
</View>
);
}Using the native Picker
For a truly native wheel/menu (system-styled on each platform), use @react-native-picker/picker. Good for settings screens; less flexible to style:
// npx expo install @react-native-picker/picker
import { Picker } from '@react-native-picker/picker';
import { useState } from 'react';
function NativePicker() {
const [value, setValue] = useState('apple');
return (
<Picker selectedValue={value} onValueChange={setValue}>
<Picker.Item label="Apple" value="apple" />
<Picker.Item label="Banana" value="banana" />
<Picker.Item label="Cherry" value="cherry" />
</Picker>
);
}Props
The props that matter for a custom Modal dropdown:
| Prop | Type | Default | Description |
|---|---|---|---|
| options | string[] | — | The list of selectable values. |
| value | string | null | null | Currently selected value (controlled). |
| onChange | fn | — | Called with the picked value. |
| placeholder | string | 'Select…' | Shown on the trigger when nothing is selected. |
| transparent | boolean | true | Modal prop — required so the backdrop shows through. |
| onRequestClose | fn | — | Modal prop — fires on Android back button. Always set it. |
Common patterns
Objects, not strings: when options are { label, value }, render item.label and call onChange(item.value); set keyExtractor to item.value.
Multi-select: keep a Setof selected values, toggle on tap, and don’t close the Modal until the user confirms.
Gotchas
- Don’t build the menu with
position: 'absolute'— it gets clipped by parentoverflowand scroll views. AModalalways floats on top. - Always set
onRequestCloseon the Modal or the Android hardware back button won’t dismiss the dropdown. - In a searchable dropdown, set
keyboardShouldPersistTaps="handled"on the FlatList or the first tap only dismisses the keyboard instead of selecting an item. - Give the backdrop
PressableanonPressthat closes the Modal, but stop propagation on the menu itself so taps inside don’t close it. - Duplicate keys crash the list. Make sure each option is unique, or derive a unique
keyExtractor.
FAQ
Does React Native have a dropdown component? No. Build one from a Modal + FlatList, or install @react-native-picker/picker.
Modal dropdown or a library?Start with the dependency-free Modal — it’s ~30 lines, works cross-platform, and adds nothing to your bundle. Reach for a library only if you need advanced features like grouped sections or async loading.
How do I make it searchable? Add a TextInput above the list and filter a memoized copy of the options (see the searchable example).