DEV Community

Cover image for Enabling multi-select dropdowns in React Native
Megan Lee for LogRocket

Posted on • Originally published at blog.logrocket.com

Enabling multi-select dropdowns in React Native

Written by Shalitha Suranga
✏️

React Native developers often have to use various form controls in their mobile apps. In some development scenarios, we may have to enable multi-selections in dropdown components.

For example, imagine you have an AI-based travel planner app and you want users to select their preferred destinations. You could list all available destinations in a multi-select dropdown to let the user choose multiple locations.

Besides inbuilt React Native form controls like buttons, switches, text inputs, and more, there are many open source community packages that offer pre-developed form controls. You can use existing multi-select dropdown packages or build one from scratch for your React Native app.
In this tutorial, we’ll use the popular react-native-sectioned-multi-select package — a better alternative to the react-native-multiple-select package. We’ll also explore how to build a multi-select dropdown from scratch with inbuilt React Native core components.

Let’s start by highlighting some standout features of the react-native-sectioned-multi-select package and then explore its customization options using practical examples, going from basic to advanced. You can follow along with the library implementation below and check out the code for the from-scratch dropdown demo that we’ll go over later.

Highlighted features of react-native-sectioned-multi-select

The react-native-sectioned-multi-select library offers many useful features for adding cross-platform, customizable, and user-friendly multi-select dropdowns on Android and iOS platforms. Let’s explore some of its key features now.

A fully-featured, customizable component with better defaults

This library offers a UI/UX-friendly, modal-based, fully-featured multi-select dropdown with a searchable sectioned multi-select list. It comes with inbuilt styles and reasonable behavioral defaults that let you satisfy your design requirements with less code.

The library also exposes numerous props to allow you to adjust the dropdown component’s default behavior and customize default styling.

UI/UX friendly design

This library’s multi-select dropdown component follows a better UI/UX-friendly design that improves user productivity. For example, the component offers an inbuilt feature that lets users select all items of a specific section by clicking on the particular section header.

Also, this multi-select dropdown component comes with a search box to help users find items quickly. Moreover, it renders the sectioned list on a modal to separate the multi-select UI from the main app screen.

Cross-platform and Expo support

The react-native-sectioned-multi-select project contains pure JavaScript code without native modules written in platform-specific languages like Kotlin, so it works with any mobile platform and Expo.

Additionally, this dropdown component renders the same visuals on Android and iOS mobile platforms since it uses cross-platform React Native core components.

Creating multi-select dropdowns with react-native-sectioned-multi-select

We discussed the highlighted features that the react-native-sectioned-multi-select library offers for creating multi-select dropdowns. Let’s use this library in a sample React Native project to explore its features and customizability options.

I’ll use an Expo project to demonstrate this library on the React Native framework. To get started with this tutorial, create a new Expo project like so:

npx create-expo-app MultiSelectDropdownDemo
cd MultiSelectDropdownDemo
Enter fullscreen mode Exit fullscreen mode

You can also set up a new React Native project without Expo via the official React Native CLI and continue with the tutorial:

npx react-native init MultiSelectDropdownDemo
cd MultiSelectDropdownDemo
Enter fullscreen mode Exit fullscreen mode

Installing required packages

Next, we need to install the react-native-sectioned-multi-select npm package. This package needs an icon object from the react-native-vector-icons/MaterialIcons, so we have to install @expo/vector-icons as well. Install both packages into your newly created Expo with the following command:

npx expo install react-native-sectioned-multi-select @expo/vector-icons 
Enter fullscreen mode Exit fullscreen mode

If you don’t use Expo, you can install packages using the following commands:

npm install react-native-sectioned-multi-select react-native-vector-icons
# --- or ---
yarn add react-native-sectioned-multi-select react-native-vector-icons
Enter fullscreen mode Exit fullscreen mode

Creating a basic multi-select dropdown

Let’s create a basic multi-select dropdown by using only the required props. We’ll add a dropdown component to select multiple vehicle types.

Add the following code to your App.js file:

import React, { useState } from 'react';
import { StyleSheet, View } from 'react-native';
import SectionedMultiSelect from 'react-native-sectioned-multi-select';
import { MaterialIcons as Icon } from '@expo/vector-icons';

const items = [
  { name: 'Cars', id: 1},
  { name: 'Vans', id: 2},
  { name: 'SUVs', id: 3},
  { name: 'Motorbikes', id: 4 },
  { name: 'Trucks', id: 5},
];

export default function App() {
  const [selectedItems, setSelectedItems] = useState([]);
  console.log('Selected:', selectedItems);

  return (
    <View style={styles.container}>
      <View>
        <SectionedMultiSelect
          items={items}
          IconRenderer={Icon}
          uniqueKey="id"
          onSelectedItemsChange={setSelectedItems}
          selectedItems={selectedItems}
        />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent: 'center',
    padding: 24,
  },
});
Enter fullscreen mode Exit fullscreen mode

If you don’t use Expo, make sure to import the icon object from react-native-vector-icons as follows:

import Icon from 'react-native-vector-icons/MaterialIcons';
Enter fullscreen mode Exit fullscreen mode

The above JSX code snippet creates a basic multi-select dropdown by importing the pre-developed SectionedMultiSelect component. Here, we used the selectedItems state field to hold an array of selected item indices, id as the unique key, and name as the display field.

You will see the following result when you run the above source code: Basic Multi Select Dropdown Implementation With Default Configuration Showing Search Bar Above Vehicle Categories Available To Select. On Next Screen, Chips Display Selected Items

Once you press the Confirm button in the dropdown modal, you’ll see selected items on the console as follows: Terminal After Tapping Confirm Button Showing Selected Item Identifiers Printed

As the library name suggests, the react-native-sectioned-multi-select library lets you group items into sections using child item arrays within dropdown item objects.

Create several vehicle models as sub-items using the items property:

const items = [
  { name: 'Cars', id: 1,
    items: [
        { name: 'Nissan Sunny', id: 100 },
        { name: 'Toyota Corolla', id: 101 },
        { name: 'Honda Civic', id: 102 },
      ]
  },
  { name: 'Vans', id: 2,
    items: [
        { name: 'Ford Transit', id: 200 },
        { name: 'Toyota Sienna', id: 201 },
      ]
  },
  { name: 'SUVs', id: 3,
    items: [
        { name: 'Toyota RAV4', id: 300 },
        { name: 'Ford Explorer', id: 301 },
      ]
  },
  { name: 'Motorbikes', id: 4,
    items: [
        { name: 'Kawasaki KX', id: 400 },
        { name: 'Ducati Panigale', id: 401 },
        { name: 'BMW Roadster', id: 402 },
      ]
  },
];
Enter fullscreen mode Exit fullscreen mode

Next, activate sub-items using the subKey property of the SectionedMultiSelect component:

<SectionedMultiSelect
  items={items}
  IconRenderer={Icon}
  uniqueKey="id"
  subKey="items"
  onSelectedItemsChange={setSelectedItems}
  selectedItems={selectedItems}
/>
Enter fullscreen mode Exit fullscreen mode

Earlier, we could select multiple vehicle types from the dropdown. Now, it’s possible to select both vehicle types and vehicle models using the new dropdown, as shown in the following preview: Sectioned Multi Select Dropdown Component Providing Ability To Select Both Vehicle Types And Models As you can see in the above preview, by default, we can select vehicle types by tapping on the parent section header.

Basic visual customizations

By default, the SectionedMultiSelect component displays selected items as tag elements, also called chips. Additionally, it shows several pre-defined text labels and implements some helpful control elements, like a Confirm button, search icon, and more, within the multi-select component.

You can customize these visuals using various props. For example, add the following component props to your app:

selectText="Choose some vehicles..."
searchPlaceholderText="Search vehicles..."
modalAnimationType="slide"
colors={{primary: '#c98422'}}
Enter fullscreen mode Exit fullscreen mode

The above props use custom texts for select box and search placeholder labels, changes the default modal animation, and changes the primary theme color. Once you use the above props with the app code, you will see the following result: Multi Select Dropdown With Customized Primary Color, Sliding Modal Animation, And Custom Labels In the previous code snippet, we used only the primary color key, but react-native-sectioned-multi-select offers many color keys to help developers implement custom color schemes for multi-select dropdowns. Browse all supported color props and defaults in the official docs.

The react-native-sectioned-multi-select library lets you add or modify child components within the main component with props. For example, headerComponent and footerComponent props let you embed extra components in the modal.

Use the following props in your multi-select component:

hideSearch={true}
expandDropDowns={true}
headerComponent={<MultiSelectHeader/>}
footerComponent={<MultiSelectFooter itemCount={selectedItems.length}/>}
Enter fullscreen mode Exit fullscreen mode

Here, we added a header and footer child components to the multi-select modal via props. Also, the hideSearch and expandDropDowns props hide the search box and auto-expand all sections, respectively.

Next, we need to define two new React functional components as follows:

function MultiSelectHeader() {
  return (
    <View style={styles.multiSelectHeader}></View>
  );
}

function MultiSelectFooter({ itemCount }) {
  return (
    <View>
      <Text
        style={styles.multiSelectFooterText}>
        {itemCount} item(s) selected.</Text>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

The above child components use several styles from the stylesheet, so update your app stylesheet with the following definitions:

multiSelectHeader: {
  height: 24,
  backgroundColor: '#c98422'
},
multiSelectFooterText: {
  padding: 12,
  marginTop: 12,
  backgroundColor: '#eee'
},
Enter fullscreen mode Exit fullscreen mode

Once you update your app source code, you will see a custom header and footer, as shown in the following preview: Multi Select Dropdown With Customized Header And Footer Components Similarly, the multi-select component offers searchIconComponent, selectedIconComponent, unselectedIconComponent, and other props for customizing default visual segments of the component.

Basic behavioral customizations

This multi-select library implements UI/UX-friendly defaults, but you can adjust them according to your app design standards and guidelines with component props.

These behavioral customizations help developers tweak their apps for better productivity and usability. For example, setting true for the readOnlyHeadings prop disables selecting parent sections as selectable items in your React Native app’s multi-select dropdown.

Consider using the following prop in the SectionedMultiSelect component for a demonstration:

readOnlyHeadings={true}
Enter fullscreen mode Exit fullscreen mode

This prop disables selecting parent sections and expands or collapses section dropdowns as shown in the following preview: Multi Select Dropdown With Section Selection Disabled And Only Ability To Select Vehicle Models, Not Types On the other hand, you can use the highlightChildren prop to disable child item selections by auto-highlighting related child items once the parent section is selected.

If you make parent sections selectable in your multi-select dropdown, you can use parentChipsRemoveChildren to remove all child items once the user clicks on a specific parent tag’s remove icon:

parentChipsRemoveChildren={true}
Enter fullscreen mode Exit fullscreen mode

The above multi-select configuration behaves as follows: Demo Of Removing Selected Child Item Chips By Removing Selected Parent Items You can also configure the component to auto-select sub-items when you tap on a specific parent element by using the following setup:

selectChildren={true}
Enter fullscreen mode Exit fullscreen mode

Now, it’s possible to select all sub-items of a parent element at once like so: Demo Of Selecting Sub Items By Tapping Section Headers

Using event handler props

The multi-select component exposes several event handler props to let developers attach event callback functions. The onSelectedItemsChange event handler prop helped us in previous examples to get the currently selected item indices array.

SectionedMultiSelect triggers the following events:

Event handler prop Handler description
onSelectedItemObjectsChange A function that returns the selected items as their original objects instead of an array of identifiers
onCancel A function that runs when the cancel button is pressed
onConfirm A function that runs when the confirm button is pressed
onToggleSelector A callback function that runs when the selector is toggled. It receives a boolean for the open/close state of the modal

Adding custom styling definitions

As we learned in previous sections, the colors prop offers a way to set a custom color theme for multi-select dropdowns. This multi-select component also offers several props to use custom font families for labels.

However, customizing colors and font families is not enough to satisfy unique design requirements, so this library lets you override internal styles via the styles prop.

Assume that you need to customize the backdrop of the modal and the multi-select input box with custom styles. You can use a custom styles object as follows for this requirement:

styles={{
  backdrop: styles.multiSelectBackdrop,
  selectToggle: styles.multiSelectBox
}}
Enter fullscreen mode Exit fullscreen mode

Here are the styling definitions that you need to add to your stylesheet:

multiSelectBackdrop: {
  backgroundColor: 'rgba(255, 183, 0, 0.2)',
},
multiSelectBox: {
  borderWidth: 1,
  borderRadius: 8,
  borderColor: '#bbb',
  padding: 12,
  marginBottom: 12
},
Enter fullscreen mode Exit fullscreen mode

The above styles object customizes the backdrop and the input box as follows: Multi Select Dropdown With Custom Styles For Select Box Backdrop Assume that you need to customize selected item tags with a custom styling setup, as shown in the following preview: Multi Select Dropdown Component With Custom Chip Styles To get the above multi-select style, you need to set custom styling definitions for chipContainer and chipText keys via the styles object:

styles={{
  backdrop: styles.multiSelectBackdrop,
  selectToggle: styles.multiSelectBox,
  chipContainer: styles.multiSelectChipContainer,
  chipText: styles.multiSelectChipText,
}}

// in stylesheet
multiSelectChipContainer: {
  borderWidth: 0,
  backgroundColor: '#ddd',
  borderRadius: 8
},
multiSelectChipText: {
  color: '#222',
  fontSize: 14.5
}
Enter fullscreen mode Exit fullscreen mode

There are about 30 different style object properties to customize the styling properties of the multi-select component. Browse all supported style object keys from the official documentation on GitHub.

Customizing the multi-select box text

Earlier, we used custom static text for the select box placeholder and search box placeholder by sending strings to selectText and searchPlaceholderText props.

By default, this library sets a dynamic text for the select box based on the following cases:

  1. Use the placeholder text if no item is selected
  2. If only one item is selected, use its display name
  3. If the user selects more than one item, use the placeholder and the “( x selected )” dynamic text together

Assume that your UI/UX standards and guidelines need to adjust the above logic as follows:

  1. Use the placeholder text if no item is selected
  2. Display selected items as an English sentence with , and and connectors (e.g., Kawasaki KX, Ducati Panigale, and BMW Roadster) only if the selected vehicle count is greater than zero and less than three
  3. Otherwise, display selected vehicles count as “x vehicle(s) selected”

Customizing select box text is possible with the renderSelectText prop. Look at the following App component code:

export default function App() {
  const [selectedItems, setSelectedItems] = useState([]);
  const [selectedItemObjects, setSelectedItemObjects] = useState([]);

  console.log('Selected:', selectedItemObjects);

  function renderSelectText() {
    let c = selectedItems.length;
    if(c <= 3) {
      return selectedItemObjects.map((item) => item.name).
            join(', ').replace(/, ([^,]*)$/, ' and $1')
    }

    if(c > 3) {
      return `${c} vehicle(s) selected`;
    }

    return 'Choose some vehicles...';
  }
  return (
    <View style={styles.container}>
      <View>
        <SectionedMultiSelect
          items={items}
          IconRenderer={Icon}
          uniqueKey="id"
          subKey="items"
          selectedItems={selectedItems}
          selectText="Choose some vehicles..."
          searchPlaceholderText="Search vehicles..."
          onSelectedItemsChange={setSelectedItems}
          onSelectedItemObjectsChange={setSelectedItemObjects}
          renderSelectText={renderSelectText}
          showChips={false}
          readOnlyHeadings={true}
        />
      </View>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Run the above code, select several items, and look at the development preview: Multi Select Dropdown Component With Custom Dynamic Select Box Text

How to implement Select all and Clear all buttons

This multi-select dropdown offers an inbuilt clear-all-items feature via the showRemoveAll prop, which renders an additional tag for clearing all selected items without opening the modal. In some scenarios, we have to select or clear all items programmatically via other UI elements. This library offers two internal methods for this requirement.

Let’s implement two buttons to select and clear all items. To access these internal methods, first, you need to create a React ref as follows:

const ref = useRef(null);

...
<SectionedMultiSelect
  ref={ref}
...
...
Enter fullscreen mode Exit fullscreen mode

Next, add the following JSX content after the SectionedMultiSelect component:

<View style={{paddingTop: 12}}>
  <Button title="Select all" onPress={() => ref && ref.current && ref.current._selectAllItems()}
/>
  <View style={{padding: 6}}/>
  <Button title="Remove all" onPress={() => ref && ref.current && ref.current._removeAllItems()}
/>
</View>
Enter fullscreen mode Exit fullscreen mode

Make sure that showChips is set to {true} in the multi-select component. Now, it’s possible to select and clear all items with two buttons, as shown in the following preview: Two Button Elements For Multi Select Dropdown Component To Select And Clear All Items Moreover, this multi-select dropdown component library exports the _toggleSelector internal method to programmatically open and close the dropdown modal.

Adding item collection icons

Developers often use sectioned multi-select dropdowns to display items with categories, so adding icons for each category container becomes a common requirement. The react-native-sectioned-multi-select library lets you set category icons by sending icon identifiers of the selected icon collection.

Let’s add some icons for the sample app’s categories. First, add icon keys to the items object as follows:

const items = [
  { name: 'Cars', id: 1, icon: 'directions-car',
    items: [
        { name: 'Nissan Sunny', id: 100 },
        { name: 'Toyota Corolla', id: 101 },
        { name: 'Honda Civic', id: 102 },
      ]
  },
  { name: 'Vans', id: 2, icon: 'airport-shuttle',
    items: [
        { name: 'Ford Transit', id: 200 },
        { name: 'Toyota Sienna', id: 201 },
      ]
  },
  { name: 'SUVs', id: 3, icon: 'car-repair',
    items: [
        { name: 'Toyota RAV4', id: 300 },
        { name: 'Ford Explorer', id: 301 },
      ]
  },
  { name: 'Motorbikes', id: 4, icon: 'motorcycle',
    items: [
        { name: 'Kawasaki KX', id: 400 },
        { name: 'Ducati Panigale', id: 401 },
        { name: 'BMW Roadster', id: 402 },
      ]
  },
];
Enter fullscreen mode Exit fullscreen mode

Next, activate icon rendering by mentioning the icon property name as follows, along with a custom style for itemText for better spacing:

<SectionedMultiSelect
  iconKey="icon"
  styles={{itemText: {marginLeft: 5, fontSize: 17}}}  
  ...
  ...
Enter fullscreen mode Exit fullscreen mode

Open the multi-select modal and look at category icons: Multi Select Dropdown Customized With Icons For Different Sections It’s possible to set icons for sub-items using the same icon property within sub-item objects. This library lets you use icons from imported local images, web URLs, and custom icon packages, as explained in the official documentation on GitHub.

Loading multi-select items from the web

We used a hard-coded static items list with previous examples, but in real-world development scenarios, we often load data from RESTful services over the internet. Let’s fetch some items from JSONPlaceholder.

Update the component source code as follows:

export default function App() {
  const [items, setItems] = useState(null);
  const [selectedItems, setSelectedItems] = useState([]);

  function loadUsers() {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(response => response.json())
      .then(users => setTimeout(() => setItems(users), 3000));
  }

  console.log('Selected:', selectedItems);

  return (
    <View style={styles.container}>
      <View>
        <SectionedMultiSelect
          items={items}
          IconRenderer={Icon}
          uniqueKey="id"
          subKey="items"
          selectedItems={selectedItems}
          selectText="Choose some users..."
          searchPlaceholderText="Search users..."
          onSelectedItemsChange={setSelectedItems}
          onToggleSelector={(opened) => opened && loadUsers()}
          loading={items === null}
        />
      </View>
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here we used the inbuilt fetch function to load users from the JSONPlaceholder RESTful web API. The loading prop helps us display a loading animation for the fake three-second network latency.

Look at the following preview: Loading Animation Displayed While Retrieving Data For Multi Select Dropdown

Creating a multi-select dropdown from scratch

The react-native-sectioned-multi-select package is a fully-featured external library. So, it increases your app bundle size, as any other npm module.

`react-native-bundle-visualizer' detects only ~30 kilobytes of JavaScript bundle increment for this multi-select library, which is negligible compared to the size of the React Native framework. However, you can also build your own, customizable multi-select dropdown component from scratch and avoid using multi-select libraries.

Let’s see how to do this now. Here is a preview of a minimal multi-select dropdown built with inbuilt React Native core components: Demo Of Multi Select Dropdown Component Built From Scratch You can browse the complete source code of this multi-select dropdown implementation from this GitHub repository. This sample multi-select dropdown uses the following behavioral logic:

  • Contains a select box with a dropdown icon that toggles up and down arrows based on the select box state
  • Once you click on the select box, a list of items will appear as a dropdown
  • The items list allows the user to select multiple items with a screen tap action
  • The component uses a dark color background to differentiate a selected item from an unselected item

You’ll notice the following implementation details when you inspect the source:

  • The MultiSelect reusable component exposes items and onSelectedItemsChange props for basic functionality
  • Once an item is pressed, the component adds the selected item identifier to the selectedItems array and calls the onSelectedItemsChange handler with the selected item identifiers

This multi-select dropdown is very minimal and has no animations, customization props, or advanced features like item search. You can extend it according to your design requirements by forking the GitHub repository.

Comparing multi-select dropdown implementation methods

Multi-select dropdown implementation is also possible with libraries like react-native-multiple-select and react-native-multi-selectbox. Let’s compare popular multi-select dropdown libraries and the from-scratch approach in a table:

Comparison factor react-native-sectioned-multi-select react-native-multiple-select Without a library (i.e., react-native-multi-select-minimal)
Rendering of items Uses a modal, so the item list won’t interfere with other app controls Doesn’t use a modal, so the item list can push down other form controls Depends on the implementation method
Inbuilt features Offers many, well-organized features with better flexibility Offers many features, but not feature-rich as react-native-sectioned-multi-select None
Pre-styled to boost developer-productivity Yes Yes No
Customizability Very good Good No customizability restrictions as when using an external library
Usage scenarios Usable for creating multi-select dropdowns in any React Native app Usable for creating multi-select dropdowns in any React Native app When you need a minimal or domain-specific advanced multi-select dropdown

According to the above comparison summary, react-native-sectioned-multi-select offers a better solution for implementing customizable multi-select dropdowns in almost all development scenarios. You can learn advanced customizations and upcoming features by browsing its GitHub repository.

However, implementing a multi-select from scratch improves your React Native skills and offers the maximum development flexibility. So, for implementing minimal or domain-specific advanced multi-selects, building your own multi-select is undoubtedly a better option.

Conclusion

In this tutorial, we learned how to create multi-select dropdowns in React Native apps with practical examples. We discussed the fully-featured react-native-sectioned-multi-select package and built one multi-select dropdown from scratch with React Native core components.

Regardless of the implementation method, consider using better UI/UX principles in multi-select components to offer better productivity for app users.


LogRocket: Instantly recreate issues in your React Native apps

LogRocket Signup

LogRocketis a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — try LogRocket for free.

Top comments (0)