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

@shaquillehinds/react-native-dropdown-selector

v0.0.7

Published

A simple dropdown selector for react native that just works.

Downloads

37

Readme

@shaquillehinds/react-native-dropdown-selector

A beautifully animated, fully customizable dropdown selector for React Native that intelligently adapts to screen position and just works out of the box.

npm version License: MIT

✨ Features

  • 🎯 Smart Positioning - Automatically detects available screen space and renders upward or downward
  • 🎨 Fully Customizable - Style every element from the button to individual items
  • 🔄 Smooth Animations - Fluid spring and timing animations with configurable parameters
  • 📱 Cross-Platform - Works seamlessly on iOS and Android with platform-specific optimizations
  • 🎭 Custom Components - Replace default components with your own React components
  • 🔍 TypeScript Support - Full type safety with generic type support
  • 🪶 Lightweight - Minimal dependencies, built on react-native-essentials
  • Accessible - Includes proper touch targets and visual feedback

📦 Installation

npm install @shaquillehinds/react-native-dropdown-selector

or

yarn add @shaquillehinds/react-native-dropdown-selector

Peer Dependencies

This package requires the following peer dependencies:

npm install react-native-gesture-handler react-native-reanimated react-native-svg

Make sure to complete the installation setup for these libraries as per their documentation.

🚀 Basic Usage

import { DropDownSelector } from '@shaquillehinds/react-native-dropdown-selector';
import { useState } from 'react';

function MyComponent() {
  const [selectedValue, setSelectedValue] = useState<string>('apple');

  const fruits = [
    { label: 'Apple', value: 'apple' },
    { label: 'Banana', value: 'banana' },
    { label: 'Orange', value: 'orange' },
    { label: 'Mango', value: 'mango' },
  ];

  return (
    <DropDownSelector
      items={fruits}
      selectedItem={selectedValue}
      onSelect={setSelectedValue}
      placeholder="Select a fruit"
    />
  );
}

🎨 Advanced Customization

Styling the Dropdown Button

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  dropdownButtonProps={{
    backgroundColor: '#007AFF',
    borderRadius: 'large',
    padding: [2, 6],
  }}
  dropdownButtonTextProps={{
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  }}
/>

Custom Icon Component

import { ChevronDown } from './icons';

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  DropdownButtonIcon={({ isOpen, expandDirection }) => (
    <ChevronDown
      color="#007AFF"
      style={{
        transform: [{ rotate: isOpen ? '180deg' : '0deg' }],
      }}
    />
  )}
/>;

Custom Dropdown Item Component

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  DropdownItemComponent={({ item, isSelected }) => (
    <View style={styles.customItem}>
      <Image source={{ uri: item.icon }} style={styles.icon} />
      <Text style={[styles.itemText, isSelected && styles.selected]}>
        {item.label}
      </Text>
      {isSelected && <CheckIcon />}
    </View>
  )}
/>

Configuring Animations

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  expandAnimationConfig={{
    type: 'spring',
    speed: 12,
    bounciness: 8,
  }}
  unMountDelayInMilliSeconds={250}
/>

Controlling Expand Direction

// Force expand upward
<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  expandDirection="up"
/>

// Force expand downward
<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  expandDirection="down"
/>

// Auto-detect (default behavior)
<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  // expandDirection not specified - automatically detects best direction
/>

Custom Expand Distance

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  expandDistance={250} // Maximum height in pixels
/>

📚 API Reference

Props

| Prop | Type | Required | Description | | ------------------------------- | --------------------------------- | -------- | ------------------------------------------------- | | items | DropDownItem<T>[] | ✅ | Array of items to display in dropdown | | selectedItem | T | ✅ | Currently selected item value | | onSelect | (item: T) => void | ✅ | Callback when an item is selected | | placeholder | string | ✅ | Placeholder text when no item is selected | | onOpen | () => void | ❌ | Callback when dropdown opens | | onClose | () => void | ❌ | Callback when dropdown closes | | unMountDelayInMilliSeconds | number | ❌ | Delay before unmounting dropdown (default: 300ms) | | isDisabled | boolean | ❌ | Disables the dropdown selector | | disableShadow | boolean | ❌ | Removes shadow from dropdown | | expandDirection | 'up' \| 'down' | ❌ | Forces dropdown to expand in specific direction | | expandDistance | number | ❌ | Maximum height for dropdown content | | expandAnimationConfig | AnimationConfig | ❌ | Custom animation configuration | | containerProps | LayoutProps | ❌ | Props for the root container | | dropdownButtonProps | RNPressableLayoutProps | ❌ | Props for the dropdown button | | dropdownButtonTextProps | BaseTextProps | ❌ | Props for the button text | | DropdownButtonIcon | Component | ❌ | Custom button icon component | | dropdownScrollViewProps | ScrollViewProps | ❌ | Props for the dropdown ScrollView | | dropdownContentContainerProps | LayoutProps | ❌ | Props for the dropdown content container | | DropdownItemComponent | Component | ❌ | Custom dropdown item component | | onDropdownItemPress | (item: DropDownItem<T>) => void | ❌ | Callback when dropdown item is pressed | | dropdownItemProps | TouchableLayoutProps | ❌ | Props for individual dropdown items | | dropdownItemTextProps | BaseTextProps | ❌ | Props for dropdown item text | | DropdownItemSelectedIcon | Component | ❌ | Custom selected item icon component |

Types

DropDownItem

type DropDownItem<T> = {
  label: string; // Display text
  value: T; // Value (can be any type)
};

AnimationConfig

type AnimationConfig =
  | (Omit<Animated.TimingAnimationConfig, 'toValue'> & { type: 'timing' })
  | (Omit<Animated.SpringAnimationConfig, 'toValue'> & { type: 'spring' });

Custom Component Props

DropdownButtonIcon

type DropdownButtonIconProps = {
  isOpen: boolean;
  expandDirection: 'up' | 'down';
};

DropdownItemComponent

type DropdownItemComponentProps<T> = {
  item: DropDownItem<T>;
  isSelected: boolean;
};

DropdownItemSelectedIcon

type DropdownItemSelectedIconProps<T> = {
  item: DropDownItem<T>;
};

🎯 Advanced Examples

With TypeScript Generics

interface User {
  id: number;
  name: string;
  email: string;
}

function UserSelector() {
  const [selectedUserId, setSelectedUserId] = useState<number>(1);

  const users: DropDownItem<number>[] = [
    { label: 'John Doe', value: 1 },
    { label: 'Jane Smith', value: 2 },
    { label: 'Bob Johnson', value: 3 },
  ];

  return (
    <DropDownSelector<number>
      items={users}
      selectedItem={selectedUserId}
      onSelect={setSelectedUserId}
      placeholder="Select a user"
    />
  );
}

With Complex Objects

interface Country {
  code: string;
  name: string;
  flag: string;
}

function CountrySelector() {
  const [selectedCountry, setSelectedCountry] = useState<string>('US');

  const countries: DropDownItem<string>[] = [
    { label: '🇺🇸 United States', value: 'US' },
    { label: '🇨🇦 Canada', value: 'CA' },
    { label: '🇬🇧 United Kingdom', value: 'GB' },
    { label: '🇦🇺 Australia', value: 'AU' },
  ];

  return (
    <DropDownSelector<string>
      items={countries}
      selectedItem={selectedCountry}
      onSelect={setSelectedCountry}
      placeholder="Select a country"
      onDropdownItemPress={(item) => {
        console.log('Selected country:', item.label);
      }}
    />
  );
}

With Lifecycle Callbacks

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  onOpen={() => {
    console.log('Dropdown opened');
    // Track analytics, pause animations, etc.
  }}
  onClose={() => {
    console.log('Dropdown closed');
    // Resume animations, save state, etc.
  }}
  onDropdownItemPress={(item) => {
    console.log('Item pressed:', item);
    // Custom handling before selection
  }}
/>

Fully Customized Theme

<DropDownSelector
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
  containerProps={{
    margin: [2, 0],
  }}
  dropdownButtonProps={{
    backgroundColor: '#1E1E1E',
    borderRadius: 'large',
    padding: [3, 5],
    borderWidth: 1,
    borderColor: '#333',
  }}
  dropdownButtonTextProps={{
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '500',
  }}
  dropdownContentContainerProps={{
    backgroundColor: '#2A2A2A',
    borderRadius: 'soft',
  }}
  dropdownItemProps={{
    padding: [3, 5],
    backgroundColor: '#2A2A2A',
  }}
  dropdownItemTextProps={{
    color: '#FFFFFF',
    fontSize: 15,
  }}
  disableShadow={false}
/>

🔧 How It Works

Smart Positioning

The dropdown automatically measures its position on the screen and determines whether there's enough space to expand downward. If not, it expands upward. This ensures the dropdown is always visible and accessible.

// The component automatically:
// 1. Measures its position using onLayout
// 2. Calculates distance to bottom of screen
// 3. Compares with expandDistance (or default maxHeight)
// 4. Renders upward if insufficient space below
// 5. Animates chevron icon to match direction

Animation System

The component uses react-native-reanimated for smooth, performant animations:

  • Dropdown expansion: Configurable spring or timing animation
  • Chevron rotation: Spring animation that follows expand direction
  • Android shadow: Timing animation for platform-specific shadow rendering

Modal Integration

Uses @shaquillehinds/react-native-essentials modal system for proper overlay handling, ensuring the dropdown appears above other content with correct z-index management.

🎨 Styling with react-native-essentials

This package leverages @shaquillehinds/react-native-essentials for its layout and styling system, which provides:

  • Predefined border radius sizes (soft, medium, large)
  • Shadow utilities with platform-specific handling
  • Responsive sizing based on device orientation
  • Flexible layout components with intuitive props

Example of essentials-powered styling:

<DropDownSelector
  dropdownButtonProps={{
    borderRadius: 'medium', // Uses predefined radius
    padding: [2, 5], // [vertical, horizontal] shorthand
    backgroundColor: 'white',
  }}
/>

🐛 Troubleshooting

Dropdown not appearing

Ensure you've installed and configured peer dependencies:

  • react-native-gesture-handler
  • react-native-reanimated
  • react-native-svg

Items not scrolling

Check that react-native-gesture-handler is properly set up in your app's entry file:

import 'react-native-gesture-handler';
// ... rest of your imports

Shadow not showing on Android

The component handles Android shadows differently. If you're still not seeing shadows, try:

  • Setting disableShadow={false} explicitly
  • Checking that your Android API level supports the shadow properties

Dropdown position incorrect

The component measures position on mount and when opened. If your layout shifts after initial render:

// Force remeasure by adding key prop when layout changes
<DropDownSelector
  key={layoutKey}
  items={items}
  selectedItem={selectedValue}
  onSelect={setSelectedValue}
  placeholder="Select option"
/>

📝 Examples Repository

For more examples and complete implementation patterns, check out the examples folder in the repository.

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide and Code of Conduct before submitting pull requests.

Development Setup

# Clone the repository
git clone https://github.com/shaquillehinds/react-native-dropdown-selector.git

# Install dependencies
yarn install

# Run the example app
yarn example start

📄 License

MIT © Shaquille Hinds

🙏 Acknowledgments

Built with:

📮 Support


Made with ❤️ by Shaquille Hinds