Skip to main content
Version: Next 🚧

Search a server

Options that come from an API. loadOptions covers most cases in one line; onSearchChange is there when you need pagination or your own cache.

With loadOptions​

Give it a function from the query to the options. The picker waits for a pause in typing, shows the loader from the keystroke until the results arrive, and ignores answers to older queries. It starts empty with searchPrompt, since options (shown before the user types) isn't passed, and says emptyText when a search finds nobody.

Loading…
<SelectPicker
  label="Assignee"
  placeholder="Search people"
  value={user}
  onChange={setUser}
  loadOptions={searchUsers}
  searchPrompt="Type a name"
  loadingText="Searching people…"
  emptyText="Nobody by that name"
  clearable
  onClear={() => setUser(null)}
/>

searchDebounce sets the wait after the last keystroke (300 ms by default; 0 searches on every keystroke). A rejected promise shows emptyText. For several fields like this in one form, see the flight search form.

With onSearchChange, and pages​

When the server pages its results, keep the options yourself: onSearchChange gives you the query once typing pauses, loading shows the loader (under the options once some are showing), and onEndReached asks for the next page.

Loading…
<SelectPicker
  label="Customer"
  options={options}
  value={customer}
  onChange={setCustomer}
  onSearchChange={setQuery}
  loading={loading}
  onEndReached={() => {
    if (hasMore && !loading) load(query, options.length);
  }}
  listHeight={280}
/>

Closing the picker calls onSearchChange(''), so the next open starts from the first page of everything.

A custom loader​

renderLoading replaces the spinner and text. Here, skeleton rows shaped like the options:

Loading…
import { StyleSheet, View } from 'react-native';
import { SelectList } from '@elik56a/react-native-pickers';
import type { PickerTheme } from '@elik56a/react-native-pickers';

const Skeleton = ({ theme }: { theme: PickerTheme }) => (
  <View style={styles.skeleton}>
    {[0.7, 0.5, 0.6].map((width) => (
      <View key={width} style={styles.row}>
        <View style={[styles.avatar, { backgroundColor: theme.colors.surface }]} />
        <View style={[styles.line, { width: `${width * 100}%`, backgroundColor: theme.colors.surface }]} />
      </View>
    ))}
  </View>
);

export default function Example() {
  return <SelectList options={[]} loading renderLoading={(theme) => <Skeleton theme={theme} />} />;
}

const styles = StyleSheet.create({
  skeleton: { flex: 1, gap: 14 },
  row: { flexDirection: 'row', alignItems: 'center', gap: 12 },
  avatar: { width: 32, height: 32, borderRadius: 16 },
  line: { height: 12, borderRadius: 6 },
});