npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-multi-selectbox

v2.0.3

Published

Platform-independent select / multi-select / picker for React Native and Expo (TypeScript).

Readme

react-native-multi-selectbox

npm version npm downloads license

Cross-platform select / multi-select / picker for React Native and Expo (iOS, Android, web). Shared UI and a TypeScript-first API.

This file is the consumer documentation source of truth (npm + GitHub).
Monorepo layout / contributor commands live in the repository root README.

Live demo

sauzy34.github.io/react-native-multi-selectbox

Example app in the monorepo: apps/example · SectionListHostDemo.tsx · ScrollViewHostDemo.tsx

Release notes: CHANGELOG.md


Table of contents


Features

  • Single- and multi-select with a consistent look on iOS, Android, and web (Expo / RNW)
  • TypeScript types with a discriminated union on isMulti
  • Searchable options (hideInputFilter to turn search off)
  • Multi-select chips with remove / toggle affordances
  • Host-safe by default: virtualized={false} uses a bounded options ScrollView (avoids nested VirtualizedList warnings under forms)
  • Opt-in virtualized FlatList for very large option lists when there is no vertical scroll parent
  • Peers: react and react-native — icons use built-in text glyphs

Install

npm install react-native-multi-selectbox
# or
yarn add react-native-multi-selectbox
# or
pnpm add react-native-multi-selectbox

Peer dependencies

| Peer | Version | | -------------- | --------------------------------- | | react | ≥ 18 | | react-native | ≥ 0.73 (Expo SDK 50+ recommended) |

No extra native modules. Works with Expo managed workflow and bare RN.

Maintainers: publish this package from packages/multi-selectbox (or pnpm publish:lib at the repo root). Do not run npm publish at the monorepo root — that package is private: true.


Quick start

Options must include id and item (string label).

import { useState } from 'react'
import { View } from 'react-native'
import SelectBox, { type SelectOption } from 'react-native-multi-selectbox'

const COUNTRIES: SelectOption[] = [
  { id: 'us', item: 'United States' },
  { id: 'ca', item: 'Canada' },
  { id: 'gb', item: 'United Kingdom' },
  { id: 'in', item: 'India' },
]

export function ProfileForm() {
  const [country, setCountry] = useState<SelectOption | Record<string, never>>({})

  return (
    <View style={{ padding: 16 }}>
      <SelectBox
        label="Country"
        inputPlaceholder="Search countries…"
        options={COUNTRIES}
        value={country}
        onChange={setCountry}
      />
    </View>
  )
}

Open the live demo for more patterns (timezone, skills chips, tags, etc.).


Examples

Single select

Controlled value via value + onChange. Empty {} / missing item means “nothing selected” (1.x-compatible).

import { useState } from 'react'
import SelectBox, { type SelectOption } from 'react-native-multi-selectbox'

const TIMEZONES: SelectOption[] = [
  { id: 'utc', item: 'UTC' },
  { id: 'pt', item: 'Pacific Time (PT)' },
  { id: 'et', item: 'Eastern Time (ET)' },
]

export function TimezoneField() {
  const [timezone, setTimezone] = useState<SelectOption>({ id: 'utc', item: 'UTC' })

  return (
    <SelectBox
      label="Timezone"
      inputPlaceholder="Find a timezone…"
      options={TIMEZONES}
      value={timezone}
      onChange={setTimezone}
    />
  )
}

Multi select

Use isMulti, selectedValues, onMultiSelect, and onTapClose (chip remove). Parent owns the list — for example with a small toggle-by-id helper:

import { useState } from 'react'
import SelectBox, { type SelectOption } from 'react-native-multi-selectbox'

const SKILLS: SelectOption[] = [
  { id: 'ts', item: 'TypeScript' },
  { id: 'rn', item: 'React Native' },
  { id: 'react', item: 'React' },
]

function toggleById(list: SelectOption[], item: SelectOption): SelectOption[] {
  return list.some((x) => x.id === item.id) ? list.filter((x) => x.id !== item.id) : [...list, item]
}

export function SkillsField() {
  const [skills, setSkills] = useState<SelectOption[]>([{ id: 'ts', item: 'TypeScript' }])

  return (
    <SelectBox
      label="Skills"
      inputPlaceholder="Add skills…"
      options={SKILLS}
      selectedValues={skills}
      onMultiSelect={(item) => setSkills((prev) => toggleById(prev, item))}
      onTapClose={(item) => setSkills((prev) => toggleById(prev, item))}
      isMulti
    />
  )
}

Reference implementation: multi cards in ScrollViewHostDemo.tsx.

Hide search / filter

For short lists, hide the filter input:

<SelectBox
  label="Department"
  options={DEPARTMENTS}
  value={department}
  onChange={setDepartment}
  hideInputFilter
/>

Styling & colors

<SelectBox
  label="Channels"
  options={CHANNELS}
  selectedValues={channels}
  onMultiSelect={...}
  onTapClose={...}
  isMulti
  arrowIconColor="#4F46E5"
  searchIconColor="#4F46E5"
  toggleIconColor="#4F46E5"
  selectedItemStyle={{ fontSize: 16, fontWeight: '500' }}
  optionsLabelStyle={{ fontSize: 15 }}
  multiOptionContainerStyle={{ backgroundColor: '#4F46E5', borderRadius: 999 }}
  multiOptionsLabelStyle={{ color: '#fff', fontWeight: '600' }}
  containerStyle={{ borderBottomColor: '#E5E7EB' }}
  inputFilterStyle={{ color: '#111827' }}
/>

Full style prop names are in Props and src/types.ts.

Large option lists

Default options rendering is a ScrollView (virtualized={false}) — safest inside forms. For large catalogs without an outer vertical scroll parent, opt into a windowed list:

<SelectBox
  label="City"
  options={MANY_CITIES}
  value={city}
  onChange={setCity}
  virtualized // FlatList + max height + nestedScrollEnabled
  listOptionProps={{ initialNumToRender: 12 }}
/>

Scrolling hosts

React Native warns when a vertical VirtualizedList (FlatList / SectionList) is nested inside a vertical ScrollView (or another VirtualizedList).

| Host screen | Recommended virtualized | | ------------------------------------- | ---------------------------- | | FlatList / SectionList row | false (default) | | Vertical ScrollView form | false (default) | | Fixed / modal without list scroll | true (opt-in, large lists) |

Copy-paste hosts in the example app:

| Pattern | File | When to use | | --------------- | ----------------------------------------------------------------------------- | ------------------------ | | SectionList | SectionListHostDemo.tsx | Long screens (preferred) | | ScrollView | ScrollViewHostDemo.tsx | Simple / short forms |

Tabs live in apps/example/App.tsx.

Multi chips use a horizontal ScrollView (content-sized chips) — that orientation does not conflict with a vertical page list.

React Native: VirtualizedList — avoid nesting vertical VirtualizedLists inside vertical ScrollViews of the same orientation without care; this library defaults to a non-virtualized options panel for that reason.


Additional controls (2.0.2+)

| Prop | Purpose | | -------------------------------- | ---------------------------------------------------- | | activeOptionsLabelStyle | Style labels of selected options in the open list | | maxSelected | Multi only — max number of selections | | optionIdKey / optionLabelKey | Map options from shapes like { id, name } | | optionsAlign | left | center | right option label alignment | | optionsMaxHeight | Options panel max height (default 180) | | defaultOpen | Start with options open | | onOpenChange | (open: boolean) => void when panel opens/closes | | editable | false disables open/close | | hideDropdownIcon | Hide the field chevron | | hideChipClose | Hide × on multi chips | | renderMultiChipLeading | Leading node on chips (e.g. avatar) |

Props

Overview of the public surface. See src/types.ts for the authoritative TypeScript definitions.

| Prop | Description | | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | options | SelectOption[]{ id, item }[] (non-arrays treated as []) | | label | Field label above the control | | inputPlaceholder | Placeholder for closed field / filter | | value / onChange | Single select (when isMulti is omitted or false) | | selectedValues / onMultiSelect / onTapClose | Multi select (isMulti: true) | | isMulti | true enables multi mode (discriminated props) | | hideInputFilter | Hide the search field in the open panel | | virtualized | false (default): options ScrollView; true: options FlatList | | listOptionProps | Extra props for options FlatList (virtualized={true}) | | listScrollViewProps | Extra props for options ScrollView (default mode) | | multiSelectInputFieldProps | Extra props for the chips horizontal ScrollView | | searchInputProps | Extra TextInput props for the filter | | listEmptyText | Empty-state copy in the options panel | | selectIcon | Custom chevron / icon node | | arrowIconColor / searchIconColor / toggleIconColor | Icon paint colors | | Style props | labelStyle, containerStyle, selectedItemStyle, optionsLabelStyle, optionContainerStyle, multiOptionContainerStyle, multiOptionsLabelStyle, multiListEmptyLabelStyle, listEmptyLabelStyle, inputFilterStyle, inputFilterContainerStyle | | width | Field width (DimensionValue, default '100%') |

Test IDs for automation: TEST_IDS (exported from the package).


Types

import SelectBox, {
  type SelectOption,
  type SelectBoxProps,
  type SelectBoxSingleProps,
  type SelectBoxMultiProps,
  type OptionsListProps,
  type OptionsScrollViewProps,
  type MultiSelectFieldProps,
  TEST_IDS,
} from 'react-native-multi-selectbox'

SelectBoxProps is a discriminated union on isMulti:

  • Single: isMulti omitted / falsevalue?, onChange?
  • Multi: isMulti: trueselectedValues?, onMultiSelect?, onTapClose?
export type SelectOption = {
  id: string | number
  item: string
}

References

| Resource | Link | | ---------------------- | ------------------------------------------------------------------------------------------------------------ | | Live web demo | sauzy34.github.io/react-native-multi-selectbox | | npm | npmjs.com/package/react-native-multi-selectbox | | Public types | src/types.ts | | Changelog | CHANGELOG.md | | Example app (monorepo) | apps/example | | Repository | github.com/sauzy34/react-native-multi-selectbox | | Issues | GitHub Issues |


License

MIT © Saurav Gupta