# @carlos3g/element-dropdown — full documentation > Single-file dump of every documentation page on https://carlos3g.github.io/element-dropdown, in stable order. > Generated at build time. For the manifest version see https://carlos3g.github.io/element-dropdown/llms.txt. --- # Accessibility Source: https://carlos3g.github.io/element-dropdown/docs/accessibility # Accessibility `@carlos3g/element-dropdown` ships sensible a11y defaults: every touchable surface is exposed to screen readers, items announce their selection state, the modal traps VoiceOver focus, and the component honours the user's reduce-motion preference. Nothing on this page requires any code change to benefit from — it's all on by default. ## Trigger Both `Dropdown` and `MultiSelect` triggers expose: - `accessibilityRole="combobox"` — screen readers announce it as a dropdown. - `accessibilityState.expanded` — `true` when the list is open. - `accessibilityState.disabled` — `true` when the `disable` prop is set. Set `accessibilityLabel` on the component to give the trigger a descriptive label, and `accessibilityHint` for an action description: ```tsx ``` The label is also propagated to the search input (as `{label} input`) and the list (as `{label} flatlist`), so tests and assistive tech can address each surface. ## List items Every list row exposes: - `accessibilityRole="button"` — TalkBack / VoiceOver announces rows as actionable. - `accessibilityState.selected` — `true` when this item matches the current value. - `accessibilityState.disabled` — `true` when `disabledField` is set and the item's value at that field is truthy. By default, the row's `accessibilityLabel` is `item[labelField]`. To use a different field, set `itemAccessibilityLabelField`: ```tsx setValue(item.id)} /> ``` Items are accessible regardless of whether you pass a component-level `accessibilityLabel`. (Earlier upstream versions silently set `accessible={false}` when the component label was missing — that gate has been removed.) ## Section headers When you use the `sections` prop, the default section header carries `accessibilityRole="header"` so VoiceOver / TalkBack's "next heading" gesture surfaces group titles: ```tsx ``` If you supply your own `renderSectionHeader`, set the role yourself. ## MultiSelect chips Each chip in the selection row exposes: - `accessibilityRole="button"` - `accessibilityHint="Double tap to remove from selection"` The decorative `ⓧ` glyph is hidden from the accessibility tree (`accessibilityElementsHidden` + `importantForAccessibility="no-hide-descendants"`) so screen readers don't read out "circled x" after the label. The chip-row container is an `accessibilityLiveRegion="polite"` region — toggling a row announces the new chip without forcing the user to navigate back to the row. ## Modal isolation The dropdown opens inside a React Native `` whose root view sets `accessibilityViewIsModal`. On iOS, this scopes VoiceOver focus to the modal contents; users can't accidentally swipe back into the screen behind the open list. ## Reduce motion Both components subscribe to the OS-level "Reduce Motion" preference via `AccessibilityInfo`. When enabled, the modal opens / closes with `animationType="none"` instead of the default platform animation. The change happens live — toggling the OS setting while a dropdown is open propagates without a remount. ## Tap target size Use [`hitSlop`](./guides/hit-slop) to expand the trigger's tap area without changing its visual layout. WCAG 2.5.5 recommends at least 44 × 44 pt; if your trigger sits in tight UI, set `hitSlop` to widen the touch target. ## Font scaling Labels and the search input respect the system font-scale setting by default. Use [`allowFontScaling`](./guides/font-scaling) to override per-component when you need to lock a fixed size for layout reasons. ## Search input The built-in search input inherits an accessibility label derived from the component's `accessibilityLabel` (`{label} input`). To set a more user-friendly label, override via `searchInputProps`: ```tsx ``` `searchInputProps` is also where to set `selectionColor`, `returnKeyType`, `autoCapitalize`, `autoFocus`, etc. for keyboard / cursor a11y. See [Search input passthrough](./guides/search-input-props). ## Known gaps - **Hardware keyboard navigation** (arrow keys, Home/End, Escape, typeahead) is not yet implemented. The component relies on touch. Tracking upstream `#228` as a follow-up; needs an active-descendant focus model that doesn't exist yet in the codebase. - **Programmatic focus management** — opening the dropdown does not auto-focus the search input, and closing does not return focus to the trigger. Adding this without device-level testing would risk regressions on Android, so it's deferred until we have a Fabric / web harness. If you hit an accessibility bug or gap not listed here, open an issue at [`carlos3g/element-dropdown`](https://github.com/carlos3g/element-dropdown/issues). --- # Introduction Source: https://carlos3g.github.io/element-dropdown/docs/intro # `react-native-element-dropdown`, maintained. `@carlos3g/element-dropdown` is a drop-in fork of [`react-native-element-dropdown`](https://github.com/hoaphantn7604/react-native-element-dropdown). Bugs get fixed, the toolchain stays current, and every release is signed. Same API, same three components (`Dropdown`, `MultiSelect`, `SelectCountry`), same props — change two lines and keep shipping. ```sh npm install @carlos3g/element-dropdown ``` ```diff - import { Dropdown } from 'react-native-element-dropdown'; + import { Dropdown } from '@carlos3g/element-dropdown'; ``` ## Why this fork exists The original package is unmaintained. A large open-issue backlog, plus clean community pull requests sitting untouched for years. If you're already on `react-native-element-dropdown`, you've likely hit one of these: - `Invariant Violation: scrollToIndex out of range` when searching long lists - The list flashes at the wrong position for a frame when you reopen it - `IDropdownRef` / `IMultiSelectRef` aren't importable when you build for web or Expo - Every item has a non-overridable `padding: 17` — `itemContainerStyle` can't shrink it - `MultiSelect` trigger uses `placeholderStyle` even after you've selected something All fixed in this fork — along with plenty more. The [release notes](https://github.com/carlos3g/element-dropdown/releases) have the per-version detail. ## Where to go next - **[Installation](./installation)** — add the package to your project. - **[Quick start](./quick-start)** — render your first `Dropdown` and `MultiSelect`. - **[Migration from upstream](./migration-from-upstream)** — what changes (and what doesn't) when moving from `react-native-element-dropdown`. - **Components** — full prop reference for [`Dropdown`](./components/dropdown), [`MultiSelect`](./components/multi-select), and [`SelectCountry`](./components/select-country). - **Guides** — copy-paste recipes for common patterns. - **[Why this fork](./why-this-fork)** — the longer version. --- # Installation Source: https://carlos3g.github.io/element-dropdown/docs/installation # Installation ## Install the package ```sh npm install @carlos3g/element-dropdown ``` ```sh yarn add @carlos3g/element-dropdown ``` ## Peer dependencies `@carlos3g/element-dropdown` declares `react` and `react-native` as `peerDependencies: "*"` — the package does not pin them. Use the `react` and `react-native` versions your app is already on. The library itself runs on everything from `react-native@0.71`+ and any matching React version. There are no native modules, no pods to link, no Gradle files to touch. Expo Managed and bare React Native both work as-is. ## Supported platforms - iOS - Android - React Native Web (via `react-native-web`) ## TypeScript TypeScript support is first-class — the package ships both the type definitions and the TypeScript source. Consumer types are re-exported from the package root: ```tsx import type { DropdownProps, IDropdownRef, MultiSelectProps, IMultiSelectRef, SelectCountryProps, ISelectCountryRef, } from '@carlos3g/element-dropdown'; ``` ## Verifying the install The fastest smoke test is rendering a minimal `Dropdown` — head to [Quick start](./quick-start). --- # Why this fork Source: https://carlos3g.github.io/element-dropdown/docs/why-this-fork # Why this fork `react-native-element-dropdown` has been a good library. At the time of writing this fork was created, the upstream had **1.3k GitHub stars, 210 forks, and roughly 1.2 million weekly npm downloads**. People rely on it. It's also effectively unmaintained. The last meaningful upstream activity was mid-2024. The issue tracker has a large backlog, and the PR queue has clean, small community fixes that have been waiting years to merge. Rather than re-architect a new dropdown library, this fork keeps what worked and fixes what didn't. ## What this fork commits to - **Same public API.** Migration is two lines: the install name and the import path. See [Migration from upstream](./migration-from-upstream). - **Bugs get fixed.** Upstream issues get triaged and landed release by release. See the [release notes](https://github.com/carlos3g/element-dropdown/releases) for what's in each version, and [`docs/upstream-triage.md`](https://github.com/carlos3g/element-dropdown/blob/master/docs/upstream-triage.md) for the roadmap. - **The toolchain stays current.** TypeScript, React Native, ESLint, Prettier, Jest — they get upgraded so this library can keep up with its consumers rather than hold them back. - **Releases are signed.** Every version is published via npm Trusted Publishing (OIDC) with provenance attestation. Anyone can verify a given tarball came from this repository's CI. ## What this fork does not try to be - A rewrite. The public API is intentionally unchanged; do not expect breaking redesigns. - A new dependency-free implementation. The same FlatList + Modal approach the upstream used is still used here. - An enterprise-supported product. This is a maintained open-source fork — no SLA, no commercial tier, no email support. Issues and pull requests are the interface. ## Open questions and follow-ups Some upstream issues are deferred because they need device-level reproduction: - Keyboard-avoidance math on iOS and Android 0.76+ (upstream `#180`, `#357`, `#339`, `#288`, `#328`). - Android 14+ `dropdownPosition="top"` behavior (`#355`). - Realme OEM positioning quirks (`#350`). These are tracked in [`docs/upstream-triage.md`](https://github.com/carlos3g/element-dropdown/blob/master/docs/upstream-triage.md). Pull requests with repro projects are welcome. ## How to help - File issues with minimal repros. - Send pull requests — ideally with a test. - Port clean upstream PRs (see the upstream-triage doc for the prioritized list). - Star the repo; it makes the fork easier to find for people who are currently on the abandoned upstream. --- # Quick start Source: https://carlos3g.github.io/element-dropdown/docs/quick-start # Quick start ## A single-select `Dropdown` ```tsx import { useState } from 'react'; import { Dropdown } from '@carlos3g/element-dropdown'; const data = [ { label: 'Apple', value: 'apple' }, { label: 'Banana', value: 'banana' }, { label: 'Cherry', value: 'cherry' }, ]; export function FruitPicker() { const [value, setValue] = useState(null); return ( setValue(item.value)} /> ); } ``` What you get out of the box: - A styled trigger that displays the placeholder or the selected label. - A modal-backed list that opens on tap and closes on outside press. - Automatic positioning above or below the trigger (set [`dropdownPosition`](./components/dropdown#behavior) to lock it). ## A `MultiSelect` ```tsx import { useState } from 'react'; import { MultiSelect } from '@carlos3g/element-dropdown'; const data = [ { label: 'Apple', value: 'apple' }, { label: 'Banana', value: 'banana' }, { label: 'Cherry', value: 'cherry' }, ]; export function FruitBasket() { const [value, setValue] = useState([]); return ( ); } ``` `MultiSelect` is controlled by `value`. Tapping an item toggles it on or off; `onChange` fires with the new array. ## With a search input Set `search={true}` and the component renders a `TextInput` above the list. By default the search matches against the label field. ```tsx setValue(item.value)} /> ``` See the [custom search](./guides/custom-search-field) and [custom matcher](./guides/custom-search-matcher) guides for more control. ## Next steps - **[Components](./components/dropdown)** — the full prop reference. - **Guides** — recipes for programmatic open/close, disabled items, nesting inside a Modal, and more. --- # Migration from upstream Source: https://carlos3g.github.io/element-dropdown/docs/migration-from-upstream import Head from '@docusaurus/Head'; # Migration from `react-native-element-dropdown` The fork is designed for drop-in migration from `react-native-element-dropdown@2.12.x`. The public API is unchanged — only the package name and import paths differ. ## The two-line change ```sh # 1. Remove the upstream and install the fork npm uninstall react-native-element-dropdown npm install @carlos3g/element-dropdown ``` ```diff // 2. Update your imports - import { Dropdown, MultiSelect, SelectCountry } from 'react-native-element-dropdown'; + import { Dropdown, MultiSelect, SelectCountry } from '@carlos3g/element-dropdown'; ``` That's it. No config file changes, no `metro.config.js` tweaks, no native rebuild. ## Is the API compatible? Yes. Every prop and every component signature from `2.12.x` works unchanged. Peer dependencies are still `react: *` and `react-native: *`. Platforms supported: iOS, Android, and React Native Web. ## Do I need to rebuild native code? No. The library has no native modules, no pods to link, no Gradle files to touch. Expo Managed and bare React Native both work as-is. ## What improves automatically after migration? Behavior changes you get for free, with no code changes: - **TypeScript types are exported as types.** Importing `IDropdownRef` or `IMultiSelectRef` no longer trips bundlers on web or Expo. - **The `scrollToIndex out of range` crash is gone.** The common crash when auto-scrolling to a selected item while searching a long list no longer fires. - **Open-time flicker is gone.** The list no longer paints for a frame at the previous open's position before snapping to the correct one. - **MultiSelect trigger label honors `selectedTextStyle`** once items are selected. Previously it stayed on `placeholderStyle`. - **Row padding is customizable.** `itemContainerStyle` can shrink (or expand) the item row. Previously the `padding: 17` was hardcoded deeper in the tree and could only be overridden via `renderItem`. - **Duplicate-key warnings from `FlatList` are gone.** The list now extracts keys from `valueField` when present. - **Accessibility is announced properly.** Triggers expose `accessibilityRole="combobox"` plus `expanded` and `disabled` states; items expose `selected` and `disabled`. ## What new props are available? All new props are optional: - **[`disabledField`](./components/dropdown#behavior)** — mark individual items as non-interactive. - **`hitSlop`** — enlarge the trigger tap target without changing layout. - **`allowFontScaling`** — respect or override the system font scale for the trigger, the search input, and item labels. - **`isInsideModal`** — tells the component it's rendered inside a React Native `` so positioning math doesn't double-count the status bar. ## Anything to watch out for? - The TS type-only re-exports now use `export type`, which means that downstream code that imported `IDropdownRef` as a **value** (e.g. via `typeof`) needs to import it as a type. In practice this trips code only if you were misusing the type in the first place. - If your project depends on the exact previous row padding of `17`, no action needed — the default is unchanged. The difference is that `itemContainerStyle` can now override it. ## Still stuck? Open an issue at [`carlos3g/element-dropdown`](https://github.com/carlos3g/element-dropdown/issues). If the same symptom appears in the upstream and it's not covered by the roadmap in [`docs/upstream-triage.md`](https://github.com/carlos3g/element-dropdown/blob/master/docs/upstream-triage.md), it's worth reporting. --- # Dropdown Source: https://carlos3g.github.io/element-dropdown/docs/components/dropdown # `Dropdown` Single-select dropdown. The user taps the trigger, picks one item from a list, and the list closes. ## Minimal example ```tsx import { useState } from 'react'; import { Dropdown } from '@carlos3g/element-dropdown'; const data = [ { label: 'Apple', value: 'apple' }, { label: 'Banana', value: 'banana' }, ]; export function FruitPicker() { const [value, setValue] = useState(null); return ( setValue(item.value)} /> ); } ``` ## Props ### Required | Prop | Type | Description | |---|---|---| | `data` | `T[]` | Flat array of items. Pass `sections` instead for grouped rendering. | | `labelField` | `keyof T` | Field on each item to use as the visible label. | | `valueField` | `keyof T` | Field on each item that identifies it uniquely. | | `onChange` | `(item: T) => void` | Fires with the selected item when the user picks from the list. | ### Sections (optional — alternative to `data`) | Prop | Type | Description | |---|---|---| | `sections` | `{ title: string; data: T[] }[]` | Groups of items rendered under section headers. When provided, `data` is ignored. See [Sectioned lists](../guides/sectioned-lists). | | `renderSectionHeader` | `(section) => ReactElement \| null` | Fully custom header renderer. | | `sectionHeaderStyle` | `ViewStyle` | Style for the default header container. | | `sectionHeaderTextStyle` | `TextStyle` | Style for the default header ``. | ### Value and display | Prop | Type | Default | Description | |---|---|---|---| | `value` | `T \| string \| null` | `undefined` | Currently selected value. Can be the full item or just the `valueField` value. | | `placeholder` | `string` | `'Select item'` | Shown when no value is selected. | | `placeholderStyle` | `TextStyle` | — | Style for the placeholder text. | | `selectedTextStyle` | `TextStyle` | — | Style for the label when an item is selected. | | `selectedTextProps` | `TextProps` | `{}` | Extra props spread onto the selected-label `` (e.g. `numberOfLines`). | ### Container and layout | Prop | Type | Default | Description | |---|---|---|---| | `style` | `ViewStyle` | — | Style for the outer wrapper. | | `containerStyle` | `ViewStyle` | — | Style for the floating list container. | | `backgroundColor` | `string` | — | Color of the scrim behind the modal in full-screen modes. | | `modalAnimationType` | `'none' \| 'slide' \| 'fade'` | RN default | Forwarded to the underlying React Native ``. When the OS "Reduce Motion" setting is on, this is always forced to `'none'`. | | `maxHeight` | `number` | `340` | Max height of the list. | | `minHeight` | `number` | `0` | Min height of the list. | | `mode` | `'default' \| 'modal' \| 'auto'` | `'default'` | `'modal'` centers the list on screen; `'auto'` measures trigger position. | | `dropdownPosition` | `'auto' \| 'top' \| 'bottom'` | `'auto'` | Force the list to open above or below the trigger. | | `inverted` | `boolean` | `true` | Reverses scroll direction when positioned above the trigger. | | `isInsideModal` | `boolean` | `false` | Set to `true` when the Dropdown is rendered inside a React Native `` so the status-bar offset isn't double-counted. See [Nest inside a Modal](../guides/nested-in-modal). | ### Items | Prop | Type | Default | Description | |---|---|---|---| | `itemContainerStyle` | `ViewStyle` | — | Style merged on top of the built-in row style. Use this to change padding. | | `itemTextStyle` | `TextStyle` | — | Style for the default item label text. | | `activeItemTextStyle` | `TextStyle` | — | Extra text style applied only to the currently-selected row. | | `activeColor` | `string` | `'#F6F7F8'` | Background color of the currently selected row in the list. | | `renderItem` | `(item: T, selected?: boolean, index?: number) => ReactElement` | — | Fully custom row renderer. Overrides the default label. The optional `index` is the row index in the current list (per-section when `sections` is used) — handy for staggered enter animations. See [Animations guide](../guides/animations). | | `disabledField` | `keyof T` | — | When set, items whose value at this field is truthy are non-interactive. | | `hideSelectedFromList` | `boolean` | `false` | When `true`, the currently selected item is removed from the rendered list. | ### Search | Prop | Type | Default | Description | |---|---|---|---| | `search` | `boolean` | `false` | Show the search input above the list. | | `searchField` | `keyof T \| (keyof T)[]` | `labelField` | Which field(s) to match against. Pass an array to search several at once. See [Custom search field](../guides/custom-search-field). | | `searchQuery` | `(keyword: string, labelValue: string) => boolean` | — | Fully custom matcher. See [Custom matcher](../guides/custom-search-matcher). | | `searchKeyboardType` | `KeyboardTypeOptions` | — | `keyboardType` for the search input (e.g. `'numeric'`, `'email-address'`). | | `searchInputProps` | `TextInputProps` | — | Extra props spread onto the underlying search `` (`selectionColor`, `returnKeyType`, `autoCapitalize`, etc.). See [Search input passthrough](../guides/search-input-props). | | `persistSearch` | `boolean` | `false` | Keep the search text across opens / selections instead of clearing it. | | `searchDebounce` | `number` | `0` | Debounce the filter pass by this many ms. The text input stays responsive; only the filter is throttled. Useful for lists in the thousands. | | `inputSearchStyle` | `ViewStyle` | — | Style for the search input. | | `searchPlaceholder` | `string` | — | Placeholder text for the search input. | | `searchPlaceholderTextColor` | `string` | `'gray'` | Placeholder color for the search input. | | `renderInputSearch` | `(onSearch: (text: string) => void) => ReactElement` | — | Fully custom search input. | | `renderSearchClearIcon` | `() => ReactElement \| null` | — | Replace only the clear glyph on the built-in search input while keeping the clear-on-press behaviour. Ignored when `renderInputSearch` is supplied. | | `onChangeText` | `(text: string) => void` | — | Fires whenever the search text changes (including when the dropdown closes). | ### Icons & trigger | Prop | Type | Default | Description | |---|---|---|---| | `iconStyle` | `ImageStyle` | — | Style for the default right-side chevron. | | `iconColor` | `string` | `'gray'` | Tint for the default right-side chevron. | | `renderLeftIcon` | `(visible?: boolean) => ReactElement \| null` | — | Custom left icon; receives whether the list is open. | | `renderRightIcon` | `(visible?: boolean) => ReactElement \| null` | — | Custom right icon; receives whether the list is open. See [Icons per state](../guides/icon-per-state). | | `renderSelectedItem` | `(visible?: boolean) => ReactElement \| null` | — | Replace the entire trigger body (left icon, label, right icon) with a custom layout. See [Custom trigger](../guides/custom-trigger). | | `renderModalHeader` | `(close: () => void) => ReactElement \| null` | — | Renders a header view above the list inside the modal. Receives a `close()` to dismiss. See [Modal header](../guides/modal-header). | ### Behavior | Prop | Type | Default | Description | |---|---|---|---| | `disable` | `boolean` | `false` | When `true`, tapping the trigger does nothing. | | `autoScroll` | `boolean` | `true` | On open, scroll the list to the currently-selected row. Ignored while the list is filtered. | | `keyboardAvoiding` | `boolean` | `true` | Lift the list when the search input raises the keyboard. | | `confirmSelectItem` | `boolean` | `false` | When `true`, selecting an item calls `onConfirmSelectItem` instead of `onChange`. | | `onConfirmSelectItem` | `(item: T) => void` | — | Called when `confirmSelectItem` is `true`. | | `closeModalWhenSelectedItem` | `boolean` | `true` | When `false`, the list stays open after a selection. | | `showsVerticalScrollIndicator` | `boolean` | `true` | Shows the vertical scroll indicator on the list. | | `flatListProps` | `Omit, 'renderItem' \| 'data'>` | — | Passthrough to the underlying `FlatList`. | | `renderEmpty` | `(searchText: string) => ReactElement \| null` | — | Custom view rendered when the list has no rows — either empty `data` / `sections` or a search that filters everything out. The callback receives the current search query so you can switch between "no data" and "no results for X" copy. | | `onEndReached` | `() => void` | — | Fires when the list scrolls within `onEndReachedThreshold` of the bottom. See [Pagination](../guides/end-reached-pagination). | | `onEndReachedThreshold` | `number` | `0.5` | Distance from the end (in viewport units) at which `onEndReached` fires. | | `excludeItems` | `T[]` | `[]` | Items to hide from the rendered list. | | `excludeSearchItems` | `T[]` | `[]` | Items that show in the list but are excluded from search matches. | ### Callbacks | Prop | Type | Description | |---|---|---| | `onFocus` | `() => void` | Fires when the list opens. | | `onBlur` | `() => void` | Fires when the list closes. | ### Text rendering | Prop | Type | Default | Description | |---|---|---|---| | `fontFamily` | `string` | — | Applied to trigger label, item labels, and the search input. | | `allowFontScaling` | `boolean` | RN default | Propagated to every `Text` and `TextInput` the component renders. | ### Accessibility | Prop | Type | Description | |---|---|---| | `accessibilityLabel` | `string` | Label for the trigger. Propagated as `{label} input` to the search field and `{label} flatlist` to the list. | | `accessibilityHint` | `string` | Hint for the trigger, announced after the label and role. | | `itemAccessibilityLabelField` | `string` | Field on each item to use for per-item `accessibilityLabel`. Defaults to `labelField`. | | `testID` | `string` | testID for the trigger. Propagated as `{testID} input` / `{testID} flatlist`. | | `itemTestIDField` | `string` | Field on each item to use as its `testID`. Defaults to `labelField`. | | `hitSlop` | `Insets \| number` | Expand the trigger's tap target. | Triggers expose `accessibilityRole="combobox"` and `accessibilityState.expanded` / `.disabled`. Items expose `accessibilityRole="button"` plus `accessibilityState.selected` and `.disabled`. The open modal is scoped with `accessibilityViewIsModal`, and the OS-level "Reduce Motion" preference disables the modal animation automatically. See [Accessibility](../accessibility). ## Imperative ref ```tsx import { useRef } from 'react'; import { Dropdown } from '@carlos3g/element-dropdown'; import type { IDropdownRef } from '@carlos3g/element-dropdown'; const ref = useRef(null);