react-native-input-select

repository·main·Indexed 41 days ago

https://github.com/azeezat/react-native-select

A customizable dropdown selection package for React Native (Android and iOS) version 2.1.12. It supports multiple selection, search capabilities, and complex list layouts including FlatList and SectionList. Features include a searchable interface, custom list headers and footers, and an imperative API to programmatically open or close the dropdown.

Tokens
10.6K
Snippets
21
Records
31
Agent score
51%

What's inside react-native-input-select

  1. Reload the application

    main

    If you need to perform a full reload to reset the app state (beyond Fast Refresh), use the following platform-specific shortcuts:

    • Android: Press the <kbd>R</kbd> key twice, or open the Dev Menu via <kbd>Ctrl</kbd> + <kbd>M</kbd> (Windows/Linux) or <kbd>Cmd ⌘</kbd> + <kbd>M</kbd> (macOS) and select "Reload".
    • iOS: Press <kbd>R</kbd> in the iOS Simulator.
  2. Build and run the iOS app

    main

    To run the iOS app, you must first ensure CocoaPods dependencies are installed.

    1. Install CocoaPods via Ruby bundler (if first time): bundle install.
    2. Install native dependencies: bundle exec pod install.
    3. Run the app using one of the commands below.

    Note: You must run bundle exec pod install every time you update native dependencies.

    # Using npm
    npm run ios
    
    # OR using Yarn
    yarn ios
  3. Wrap your app in SafeAreaProvider

    main

    To ensure consistent layout behavior across devices (especially on iOS with notches and status bars) and to avoid deprecation warnings, you must wrap your root component with SafeAreaProvider from react-native-safe-area-context.

    import { SafeAreaProvider } from 'react-native-safe-area-context';
    import App from './App';
    
    export default function Root() {
      return (
        <SafeAreaProvider>
          <App />
        </SafeAreaProvider>
      );
    }
  4. Advanced usage with Flat List features

    main

    For more complex requirements, the Dropdown component supports several advanced features when used with a Flat List implementation:

    • Multiple Selection: Use isMultiple to allow selecting more than one item.
    • Search: Use isSearchable to enable a search bar within the dropdown.
    • Custom List Components: Use listHeaderComponent and listFooterComponent to add custom UI to the top or bottom of the list.
    • List Controls: Customize text for selecting/unselecting all items via listControls (selectAllText, unselectAllText, selectAllCallback, unselectAllCallback, emptyListMessage).
    • Styling: Customize the dropdown appearance via dropdownStyle, the list via listComponentStyles (e.g., itemSeparatorStyle, sectionHeaderStyle), and the modal via modalControls.
    import React from 'react';
    import Dropdown from 'react-native-input-select';
    import { View, StyleSheet, Text, Button, Alert, Image } from 'react-native';
    
    export default function App() {
      const [country, setCountry] = React.useState();
    
      return (
        <Dropdown
          label="Customized components in list"
          placeholder="Select multiple countries..."
          options={countries.slice(0, 30)}
          optionLabel={'name'}
          optionValue={'code'}
          selectedValue={country}
          onValueChange={(itemValue: any) => setCountry(itemValue)}
          isMultiple
          isSearchable
          primaryColor={'orange'}
          dropdownStyle={{
            borderWidth: 0,
          }}
          dropdownIcon={
            <Image
              style={styles.tinyLogo}
              source={{ uri: 'data:image/png;base64,...' }}
            />
          }
          dropdownIconStyle={{ top: 20, right: 20 }}
          listHeaderComponent={
            <View style={styles.customComponentContainer}>
              <Text style={styles.text}>💡 You can add any component to the top of this list</Text>
              <View style={styles.fixToText}>
                <Button title="Left button" onPress={() => Alert.alert('Left button pressed')} color="#007AFF" />
                <Button title="Right button" onPress={() => Alert.alert('Right button pressed')} />
              </View>
            </View>
          }
          listFooterComponent={
            <View style={styles.customComponentContainer}>
              <Text>You can add any component to the bottom of this list</Text>
            </View>
          }
          modalControls={{
            modalOptionsContainerStyle: {
              padding: 10,
              backgroundColor: 'cyan',
            },
            modalProps: {
              supportedOrientations: ['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right'],
              transparent: false,
            },
          }}
          listComponentStyles={{
            listEmptyComponentStyle: { color: 'red' },
            itemSeparatorStyle: {
              opacity: 0,
              borderColor: 'white',
              borderWidth: 2,
              backgroundColor: 'cyan',
            },
            sectionHeaderStyle: {
              padding: 10,
              backgroundColor: 'cyan',
            },
          }}
          listControls={{
            selectAllText: 'Choose everything',
            unselectAllText: 'Remove everything',
            selectAllCallback: () => Alert.alert('You selected everything'),
            unselectAllCallback: () => Alert.alert('You removed everything'),
            emptyListMessage: 'No record found',
          }}
          selectedItemsControls={{
            removeItemIcon: (
              <Image
                source={{ uri: 'data:image/png;base64,...' }}
                style={{ tintColor: 'white', height: 12, width: 12 }}
              />
            ),
            onRemoveItem: () => Alert.alert('Item was removed'),
            showRemoveIcon: true,
          }}
        />
      );
    }
    
    const styles = StyleSheet.create({
      customComponentContainer: { paddingHorizontal: 20, paddingVertical: 10 },
      text: { marginBottom: 20 },
      fixToText: { flexDirection: 'row', justifyContent: 'space-between' },
      tinyLogo: { width: 20, height: 20 },
      radioButton: { width: 20, height: 20, borderRadius: 10, borderWidth: 3, borderColor: 'white' },
    });
  5. Define data structures for TFlatList and TSectionList

    main

    The options prop accepts two main data formats:

    Flat List (TFlatList)

    An array of TFlatListItem objects. Each object is a dictionary where keys map to values (strings, numbers, booleans, or React elements).

    const options: TFlatList = [
      { label: 'Option 1', value: '1' },
      { label: 'Option 2', value: '2' }
    ];

    Section List (TSectionList)

    An array of TSectionListItem objects, used for grouped data.

    const options: TSectionList = [
      {
        title: 'Group 1',
        data: [{ label: 'Item 1', value: 'v1' }]
      }
    ];
  6. Configure DropdownSelect selection modes

    main

    The DropdownSelect component behaves differently based on the isMultiple prop.

    Single Selection (Default)

    • isMultiple: false (default).
    • selectedValue: Should be a single value (e.g., string or number).
    • onValueChange: Returns the single selected value.

    Multiple Selection

    • isMultiple: true.
    • selectedValue: Should be an array of values (e.g., string[]).
    • onValueChange: Returns an array of selected values.
    • Select All Feature: When isMultiple is true, a 'Select all' or 'Clear all' checkbox is automatically available in the list header if there are more than one option. You can customize the text using listControls.selectAllText and listControls.unselectAllText.
  7. Advanced usage with Section List

    main

    To use a SectionList within the dropdown, provide an array of objects to the options prop. Each object should have a title and a data array containing the items for that section.

    <DropdownSelect
      label="Menu"
      placeholder="Select multiple dishes..."
      options={[
        {
          title: 'Main dishes',
          data: [
            { label: 'Pizza', value: 'A' },
            { label: 'Burger', value: 'B' },
            { label: 'Risotto', value: 'C' },
          ],
        },
        {
          title: 'Sides',
          data: [
            { label: 'Ice cream', value: 'D' },
            { label: 'Cheesecake', value: 'E' },
          ],
        },
        {
          title: 'Drinks',
          data: [
            { label: 'Water', value: 'F' },
            { label: 'Coke', value: 'G' },
            { label: 'Juice', value: 'H' },
          ],
        },
      ]}
      selectedValue={menu}
      onValueChange={(itemValue: any) => setMenu(itemValue)}
      isMultiple
      isSearchable
      primaryColor={'deepskyblue'}
      listComponentStyles={{
        sectionHeaderStyle: {
          padding: 10,
          backgroundColor: 'green',
          color: 'white',
          width: '30%',
        },
      }}
    />
  8. Basic usage of the Dropdown component

    main

    The Dropdown component provides a simple selection interface. You can pass a label, a placeholder, an array of options (each containing label and value), the currently selected value, and an onValueChange callback.

    import React from 'react';
    import Dropdown from 'react-native-input-select';
    
    export default function App() {
      const [country, setCountry] = React.useState();
    
      return (
        <Dropdown
          label="Country"
          placeholder="Select an option..."
          options={[
            { label: 'Nigeria', value: 'NG' },
            { label: 'Åland Islands', value: 'AX' },
            { label: 'Algeria', value: 'DZ' },
            { label: 'American Samoa', value: 'AS' },
            { label: 'Andorra', value: 'AD' },
          ]}
          selectedValue={country}
          onValueChange={(value) => setCountry(value)}
          primaryColor={'green'}
        />
      );
    }
  9. Configure Metro for react-native-input-select monorepo/library structure

    main

    When using this project as a library or within a monorepo, the metro.config.js is configured to handle peer dependency resolution and module aliasing. It uses watchFolders to monitor both the project root and the local library source. To prevent conflicts, it uses a blockList to ignore specific node_modules paths and extraNodeModules to force all dependencies (including React) to resolve from the local node_modules directory of the project.

    const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
    const path = require('path');
    const pak = require('../package.json');
    const escape = require('escape-string-regexp');
    
    const root = path.resolve(__dirname, '..');
    const localLib = path.resolve(root, 'src');
    
    const modules = Object.keys({ ...pak.peerDependencies, ...pak.dependencies });
    
    const config = {
      projectRoot: __dirname,
      watchFolders: [root, localLib],
      resolver: {
        blockList: modules.map(
          m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\/.*$\/),
        ),
        extraNodeModules: modules.reduce((acc, name) => {
          acc[name] = path.join(__dirname, 'node_modules', name);
          return acc;
        }, {}),
      },
      transformer: {
        getTransformOptions: async () => ({
          transform: {
            experimentalImportSupport: false,
            inlineRequires: true,
          },
        }),
      },
    };
    
    module.exports = mergeConfig(getDefaultConfig(__dirname), config);