rn-auto-dropdown
v2.1.3
Published
Dropdown Item picker with search and autocomplete (typeahead) functionality for react native
Downloads
17
Maintainers
Readme
react-native-autocomplete-dropdown
Dropdown Item picker with search and autocomplete (typeahead) functionality for react native
Demo
Run expo snack demo @onmotion/react-native-autocomplete-dropdown
Nav
Installation
Run: npm install --save react-native-autocomplete-dropdown
or yarn add react-native-autocomplete-dropdown
Post-install Steps
Make sure react-native-vector-icons is installed. Follow the guides https://github.com/oblador/react-native-vector-icons
yarn add react-native-vector-icons
iOS
Run: npx pod-install
for install react-native-vector-icons dependency (if not installed yet).
Android
Follow the guides from https://github.com/oblador/react-native-vector-icons#android for install react-native-vector-icons dependency (if not installed yet).
Usage
import the package
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
Dataset item format
dataSet
property must be an array of objects or null. Object required keys are:
{
id: 'some uniq string id',
title: 'list item title'
}
Example with local Dataset
const [selectedItem, setSelectedItem] = useState(null);
<AutocompleteDropdown
clearOnFocus={false}
closeOnBlur={true}
closeOnSubmit={false}
initialValue={{ id: '2' }} // or just '2'
onSelectItem={setSelectedItem}
dataSet={[
{ id: '1', title: 'Alpha' },
{ id: '2', title: 'Beta' },
{ id: '3', title: 'Gamma' },
]}
/>;
Example with remote requested Dataset
import React, { memo, useCallback, useRef, useState } from 'react'
import { Button, Dimensions, Text, View, Platform } from 'react-native'
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown'
import Feather from 'react-native-vector-icons/Feather'
Feather.loadFont()
export const RemoteDataSetExample2 = memo(() => {
const [loading, setLoading] = useState(false)
const [suggestionsList, setSuggestionsList] = useState(null)
const [selectedItem, setSelectedItem] = useState(null)
const dropdownController = useRef(null)
const searchRef = useRef(null)
const getSuggestions = useCallback(async q => {
const filterToken = q.toLowerCase()
console.log('getSuggestions', q)
if (typeof q !== 'string' || q.length < 3) {
setSuggestionsList(null)
return
}
setLoading(true)
const response = await fetch('https://jsonplaceholder.typicode.com/posts')
const items = await response.json()
const suggestions = items
.filter(item => item.title.toLowerCase().includes(filterToken))
.map(item => ({
id: item.id,
title: item.title,
}))
setSuggestionsList(suggestions)
setLoading(false)
}, [])
const onClearPress = useCallback(() => {
setSuggestionsList(null)
}, [])
const onOpenSuggestionsList = useCallback(isOpened => {}, [])
return (
<>
<View
style={[
{ flex: 1, flexDirection: 'row', alignItems: 'center' },
Platform.select({ ios: { zIndex: 1 } }),
]}>
<AutocompleteDropdown
ref={searchRef}
controller={controller => {
dropdownController.current = controller
}}
// initialValue={'1'}
direction={Platform.select({ ios: 'down' })}
dataSet={suggestionsList}
onChangeText={getSuggestions}
onSelectItem={item => {
item && setSelectedItem(item.id)
}}
debounce={600}
suggestionsListMaxHeight={Dimensions.get('window').height * 0.4}
onClear={onClearPress}
// onSubmit={(e) => onSubmitSearch(e.nativeEvent.text)}
onOpenSuggestionsList={onOpenSuggestionsList}
loading={loading}
useFilter={false} // set false to prevent rerender twice
textInputProps={{
placeholder: 'Type 3+ letters (dolo...)',
autoCorrect: false,
autoCapitalize: 'none',
style: {
borderRadius: 25,
backgroundColor: '#383b42',
color: '#fff',
paddingLeft: 18,
},
}}
rightButtonsContainerStyle={{
right: 8,
height: 30,
alignSelf: 'center',
}}
inputContainerStyle={{
backgroundColor: '#383b42',
borderRadius: 25,
}}
suggestionsListContainerStyle={{
backgroundColor: '#383b42',
}}
containerStyle={{ flexGrow: 1, flexShrink: 1 }}
renderItem={(item, text) => <Text style={{ color: '#fff', padding: 15 }}>{item.title}</Text>}
ChevronIconComponent={<Feather name="chevron-down" size={20} color="#fff" />}
ClearIconComponent={<Feather name="x-circle" size={18} color="#fff" />}
inputHeight={50}
showChevron={false}
closeOnBlur={false}
// showClear={false}
/>
<View style={{ width: 10 }} />
<Button style={{ flexGrow: 0 }} title="Toggle" onPress={() => dropdownController.current.toggle()} />
</View>
<Text style={{ color: '#668', fontSize: 13 }}>Selected item id: {JSON.stringify(selectedItem)}</Text>
</>
)
})
More examples see at https://github.com/onmotion/react-native-autocomplete-dropdown/tree/main/example
Run
cd example
yarn install
yarn add react-native-vector-icons
npx pod-install
npm run ios
Options
| Option | Description | Type | Default |
|--- |--- |--- |--- |
| dataSet
| set of list items | array | null |
| initialValue
| string (id) or object that contain id | string | object | null |
| loading
| loading state | bool | false |
| useFilter
| whether use local filter by dataSet (useful set to false for remote filtering to prevent rerender twice) | bool | true |
| showClear
| show clear button | bool | true |
| showChevron
| show chevron (open/close) button | bool | true |
| closeOnBlur
| whether to close dropdown on blur | bool | false |
| closeOnSubmit
| whether to close dropdown on submit | bool | false |
| clearOnFocus
| whether to clear typed text on focus | bool | true |
| debounce
| wait ms before call onChangeText
| number | 0 |
| suggestionsListMaxHeight
| max height of dropdown | number | 200 |
| direction
| "up" or "down" | string | down + auto calculate |
| position
| "relative" or "absolute" | string | relative |
| bottomOffset
| for calculate dropdown direction (e.g. tabbar) | number | 0 |
| onChangeText
| event textInput onChangeText | function | |
| onSelectItem
| event onSelectItem | function | |
| onOpenSuggestionsList
| event onOpenSuggestionsList | function | |
| onChevronPress
| event onChevronPress | function | |
| onClear
| event on clear button press | function | |
| onSubmit
| event on submit KB button press | function | |
| onBlur
| event fired on text input blur | function | |
| onFocus
| event on focus text input | function | |
| renderItem
| JSX for render item (item, searchText) => JSX \| null
if return null then the element will not be displayed | function | item.title |
| controller
| return reference to module controller with methods close, open, toggle, clear, setInputText, setItem | function | |
| containerStyle
| | ViewStyle | |
| rightButtonsContainerStyle
| | ViewStyle | |
| suggestionsListContainerStyle
| | ViewStyle | |
| suggestionsListTextStyle
| | TextStyle | styles of suggestions list text items |
| ChevronIconComponent
| | React.Component | Feather chevron icon |
| ClearIconComponent
| | React.Component | Feather x icon |
| ~~ScrollViewComponent~~ | removed in 2.0.0 based on FlatList | React.Component name | ScrollView that provide suggestions content |
| EmptyResultComponent
| replace the default `` Component on empty result | React.Component | |
| InputComponent
| input element component | React.ComponentType | TextInput |
| emptyResultText
| replace the default "Nothing found" text on empty result | string | "Nothing found" |
| textInputProps
| text input props | TextInputProps | |
| flatListProps
| props for \ component | FlatListProps\ | |
Troubleshooting
zIndex hell on iOS
As decribed here https://docs.expo.dev/ui-programming/z-index/ on iOS for absolute positioned items we must respect the zIndex of the element parent.
So for example if you do smth like
<View style={[styles.section]}>
<Text style={styles.sectionTitle}>First</Text>
<AutocompleteDropdown
dataSet={[
{ id: '1', title: 'Alpha' },
{ id: '2', title: 'Beta' },
{ id: '3', title: 'Gamma' },
]}
/>
</View>
<View style={[styles.section]}>
<Text style={styles.sectionTitle}>Second</Text>
<AutocompleteDropdown
dataSet={[
{ id: '1', title: 'Alpha' },
{ id: '2', title: 'Beta' },
{ id: '3', title: 'Gamma' },
]}
/>
</View>
you would see
But if it change with calculated zIndex:
<View
style={[styles.section, Platform.select({ ios: { zIndex: 10 } })]}>
<Text style={styles.sectionTitle}>First</Text>
<AutocompleteDropdown
dataSet={[
{ id: '1', title: 'Alpha' },
{ id: '2', title: 'Beta' },
{ id: '3', title: 'Gamma' },
]}
/>
</View>
<View
style={[styles.section, Platform.select({ ios: { zIndex: 9 } })]}>
<Text style={styles.sectionTitle}>Second</Text>
<AutocompleteDropdown
dataSet={[
{ id: '1', title: 'Alpha' },
{ id: '2', title: 'Beta' },
{ id: '3', title: 'Gamma' },
]}
/>
</View>
it will be rendered as expected
And the same, if you want render dropdown list to up direction, you should switch zIndexes respectively
More info about this behaviour: https://docs.expo.dev/ui-programming/z-index/