Skip to content

Repository files navigation

theReactSelect

A beautiful, fast, and accessible React Select component library built with TypeScript and Tailwind CSS. No external dependencies except React.

🌟 Live Demo

🚀 View Live Demo & Playground

Experience all features including:

  • Interactive Playground - Test all configurations in real-time
  • Live Examples - See components in action
  • Complete Documentation - API reference and usage guides
  • Dark/Light Mode - Toggle themes to see both modes
  • Copy-Paste Code - Generated code for immediate use

Features

Beautiful Design - Clean, modern interface with smooth animations
🚀 High Performance - Optimized for performance with minimal re-renders
Fully Accessible - ARIA compliant with keyboard navigation
🎨 Highly Customizable - Multiple variants, sizes, and styling options
Mobile Friendly - Touch-optimized for mobile devices
�🔍 Searchable - Built-in search functionality with debounced input
�️ Multi-select - Support for selecting multiple options with badges
🎯 TypeScript - Full TypeScript support with comprehensive types
🌙 Dark Mode - Built-in dark theme support
🧩 Zero Dependencies - Only peer dependencies on React
Select All - Bulk selection for multi-select mode
🎨 Badge Variants - Multiple badge styles for different use cases
Flexible Display - Multiple ways to display selected items
🔢 Numbered Options - Optional numbering for better UX
👥 Grouped Options - Support for option grouping
🎛️ Custom Icons - Support for icons in options
📝 Rich Options - Options with descriptions and badges
🎪 Loading States - Built-in loading and error states
🧹 Clearable - Optional clear functionality
⌨️ Keyboard Navigation - Full keyboard support
🎭 Multiple Variants - Different visual styles to choose from

Installation

💡 Try it first: Check out the live demo and playground before installing!

# npm
npm install thereactselect
# pnpm 
pnpm add thereactselect
# yarn
yarn add thereactselect
# bun
bun add thereactselect

bun add thereactselect

Required CSS Variables

Add these CSS variables to your globals.css (Next.js) or index.css (React):

For Tailwind CSS v4 (Next.js)

@import'tailwindcss';
:root {
--background:00%100%;
--foreground:222.284%4.9%;
--card:00%100%;
--card-foreground:222.284%4.9%;
--popover:00%100%;
--popover-foreground:222.284%4.9%;
--primary:221.283.2%53.3%;
--primary-foreground:21040%98%;
--secondary:21040%96%;
--secondary-foreground:222.284%4.9%;
--muted:21040%96%;
--muted-foreground:215.416.3%46.9%;
--accent:21040%96%;
--accent-foreground:222.284%4.9%;
--destructive:084.2%60.2%;
--destructive-foreground:21040%98%;
--border:214.331.8%91.4%;
--input:214.331.8%91.4%;
--ring:221.283.2%53.3%;
--radius:0.5rem;
}
.dark {
--background:222.284%4.9%;
--foreground:21040%98%;
--card:222.284%4.9%;
--card-foreground:21040%98%;
--popover:222.284%4.9%;
--popover-foreground:21040%98%;
--primary:217.291.2%59.8%;
--primary-foreground:222.284%4.9%;
--secondary:217.232.6%17.5%;
--secondary-foreground:21040%98%;
--muted:217.232.6%17.5%;
--muted-foreground:21520.2%65.1%;
--accent:217.232.6%17.5%;
--accent-foreground:21040%98%;
--destructive:062.8%30.6%;
--destructive-foreground:21040%98%;
--border:217.232.6%17.5%;
--input:217.232.6%17.5%;
--ring:224.376.3%94.1%;
}

For Traditional Tailwind CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
/* Add the same CSS variables as above */

Quick Start

import{Select}from'thereactselect';constoptions=[{value: 'apple',label: 'Apple'},{value: 'banana',label: 'Banana'},{value: 'orange',label: 'Orange'},];functionApp(){return(<Selectoptions={options}placeholder="Select a fruit..."onValueChange={(value)=>console.log(value)}/>);}

Examples

Basic Select

importReact,{useState}from'react';import{Select}from'thereactselect';constoptions=[{value: 'apple',label: 'Apple'},{value: 'banana',label: 'Banana'},{value: 'orange',label: 'Orange'},];functionBasicExample(){const[value,setValue]=useState();return(<Selectoptions={options}value={value}onValueChange={setValue}placeholder="Select a fruit..."/>);}

Multi Select

functionMultiSelectExample(){const[values,setValues]=useState([]);return(<Selectoptions={options}multiplevalue={values}onValueChange={setValues}placeholder="Select multiple fruits..."/>);}

Multi Select with Select All

functionSelectAllExample(){const[values,setValues]=useState([]);return(<Selectoptions={options}multipleselectAllselectAllLabel="Select All Fruits"value={values}onValueChange={setValues}placeholder="Choose fruits..."/>);}

Searchable Select

functionSearchableExample(){const[value,setValue]=useState();return(<Selectoptions={options}searchablevalue={value}onValueChange={setValue}placeholder="Search fruits..."searchPlaceholder="Type to search..."/>);}

With Icons and Descriptions

import{Heart,Star,Award}from'lucide-react';constrichOptions=[{value: 'favorite',label: 'Favorite',icon: Heart,description: 'Your most loved option',badge: 'Popular',badgeVariant: 'success'},{value: 'starred',label: 'Starred',icon: Star,description: 'Marked with a star',badge: 'New',badgeVariant: 'warning'},{value: 'premium',label: 'Premium',icon: Award,description: 'Premium tier option',badge: 'Pro',badgeVariant: 'default'},];functionRichOptionsExample(){const[value,setValue]=useState();return(<Selectoptions={richOptions}value={value}onValueChange={setValue}placeholder="Select an option..."/>);}

Grouped Options

constgroupedOptions={groups: [{label: 'Fruits',options: [{value: 'apple',label: 'Apple'},{value: 'banana',label: 'Banana'},]},{label: 'Vegetables',options: [{value: 'carrot',label: 'Carrot'},{value: 'lettuce',label: 'Lettuce'},]}]};functionGroupedExample(){const[value,setValue]=useState();return(<Select{...groupedOptions}value={value}onValueChange={setValue}placeholder="Select food..."/>);}

Different Sizes and Variants

// Sizes<Selectoptions={options}size="sm"placeholder="Small"/><Selectoptions={options}size="default"placeholder="Default"/><Selectoptions={options}size="lg"placeholder="Large"/>// Variants<Selectoptions={options}variant="default"placeholder="Default variant"/><Selectoptions={options}variant="outline"placeholder="Outline variant"/>

States and Loading

// Loading state<Selectoptions={options}loadingplaceholder="Loading..."/>// Error state<Selectoptions={options}errorplaceholder="Error state..."/>// Success state <Selectoptions={options}successplaceholder="Success state..."/>// Disabled<Selectoptions={options}disabledplaceholder="Disabled..."/>

Clearable and Custom Display

// Clearable<Selectoptions={options}clearablevalue={value}onValueChange={setValue}placeholder="Clearable select..."/>// Multi-select with different display modes<Selectoptions={options}multipleselectedItemsDisplay="count"maxSelectedItemsToShow={2}value={values}onValueChange={setValues}placeholder="Display as count..."/><Selectoptions={options}multipleselectedItemsDisplay="text"value={values}onValueChange={setValues}placeholder="Display as text..."/>

Numbered Options

<Selectoptions={options}numberedvalue={value}onValueChange={setValue}placeholder="Numbered options..."/>// Custom number format<Selectoptions={options}numberednumberFormat={(index)=>`${index+1})`}value={value}onValueChange={setValue}placeholder="Custom numbering..."/>

Scrollable Dropdown with Custom Height

// Default scrollable dropdown (300px max height)<Selectoptions={longListOfOptions}searchableplaceholder="Select from many options..."/>// Custom max height<Selectoptions={longListOfOptions}searchablescrollablemaxHeight={500}placeholder="Taller dropdown..."/>// Disable scrolling (shows all options)<Selectoptions={options}scrollable={false}placeholder="No scrolling..."/>

API Reference

Types

SelectOption

interfaceSelectOption{value: string|number;label: string;disabled?: boolean;icon?: React.ComponentType<{className?: string}>;description?: string;badge?: string;badgeVariant?: 'default'|'secondary'|'success'|'warning'|'error'|'outline';}

SelectGroup

interfaceSelectGroup{label: string;options: SelectOption[];}

Main Component Props

PropTypeDefaultDescription
Basic Props
optionsSelectOption[][]Array of options to display
groupsSelectGroup[]undefinedGrouped options (alternative to options)
valuestring | number | (string | number)[]undefinedCurrent selected value(s)
defaultValuestring | number | (string | number)[]undefinedDefault selected value(s)
placeholderstring"Select..."Placeholder text when no selection
onValueChange(value: any) => voidundefinedCallback when selection changes
Selection Modes
multiplebooleanfalseEnable multi-select mode
selectAllbooleanfalseShow "Select All" option (multi-select only)
selectAllLabelstring"Select All"Label for select all option
Search & Filter
searchablebooleanfalseEnable search functionality
searchPlaceholderstring"Search..."Placeholder for search input
searchValuestringundefinedControlled search value
onSearchChange(value: string) => voidundefinedCallback when search changes
Interaction
clearablebooleanfalseShow clear button when value selected
disabledbooleanfalseDisable the entire component
loadingbooleanfalseShow loading spinner
closeOnSelectbooleantrueClose dropdown after selecting an option
onOpenChange(open: boolean) => voidundefinedCallback when dropdown opens/closes
Dropdown Behavior
scrollablebooleantrueEnable scrolling when content exceeds maxHeight
maxHeightnumber300Maximum height of dropdown in pixels
Styling & Variants
variant"default" | "outline""default"Visual style variant
size"sm" | "default" | "lg""default"Size variant
errorbooleanfalseShow error state styling
successbooleanfalseShow success state styling
Multi-Select Display
selectedItemsDisplay"badges" | "text" | "count""badges"How to display selected items
maxSelectedItemsToShownumber3Max items before showing count
showItemClearButtonsbooleantrueShow X buttons on individual badges
Options Display
numberedbooleanfalseShow numbers next to options
numberFormat(index: number) => stringundefinedCustom number formatting function
Groups Configuration
showGroupHeadersbooleantrueShow group header labels
groupDividersbooleanfalseShow dividers between groups
Messages
noOptionsMessagestring"No options available"Message when no options
noSearchResultsMessagestring"No results found"Message when search yields no results
Styling Overrides
classNamestringundefinedAdditional CSS classes for container
triggerClassNamestringundefinedCSS classes for trigger button
dropdownClassNamestringundefinedCSS classes for dropdown
optionClassNamestringundefinedCSS classes for options
maxHeightnumber300Maximum height of dropdown in pixels

Badge Variants

The badgeVariant prop on options supports these variants:

VariantDescriptionStyling
defaultPrimary brand colorBlue theme colors
secondaryMuted appearanceGray theme colors
successPositive/success stateGreen theme colors
warningWarning/attention stateYellow/orange theme colors
errorError/danger stateRed theme colors
outlineTransparent with borderBorder with theme colors

Selected Items Display Modes

When using multi-select, you can control how selected items are displayed:

ModeDescription
badgesShow individual badges for each selected item (default)
textShow selected items as comma-separated text
countShow count of selected items (e.g., "3 items selected")

Keyboard Navigation

KeyAction
Arrow DownMove to next option
Arrow UpMove to previous option
EnterSelect highlighted option
SpaceSelect highlighted option
EscapeClose dropdown
TabMove focus to next element

Accessibility Features

  • ARIA Compliance: Full ARIA attributes for screen readers
  • Keyboard Navigation: Complete keyboard support
  • Focus Management: Proper focus handling and visual indicators
  • Screen Reader Support: Descriptive labels and announcements
  • High Contrast: Supports high contrast mode
  • Role Attributes: Proper semantic roles for all elements

Styling and Theming

theReactSelect uses Tailwind CSS and CSS variables for theming. The component is fully themeable and supports dark mode out of the box.

CSS Variables Reference

The component uses these CSS variables for consistent theming:

:root {
/* Layout Colors */--background:00%100%; /* Main background */--foreground:222.284%4.9%; /* Main text color */--card:00%100%; /* Card backgrounds */--card-foreground:222.284%4.9%; /* Card text */--popover:00%100%; /* Popover background */--popover-foreground:222.284%4.9%; /* Popover text *//* Brand Colors */--primary:221.283.2%53.3%; /* Primary brand color */--primary-foreground:21040%98%; /* Primary text */--secondary:21040%96%; /* Secondary backgrounds */--secondary-foreground:222.284%4.9%; /* Secondary text *//* UI Colors */--muted:21040%96%; /* Muted backgrounds */--muted-foreground:215.416.3%46.9%; /* Muted text */--accent:21040%96%; /* Accent backgrounds */--accent-foreground:222.284%4.9%; /* Accent text */--destructive:084.2%60.2%; /* Error/danger color */--destructive-foreground:21040%98%; /* Error text *//* Borders and Inputs */--border:214.331.8%91.4%; /* Border color */--input:214.331.8%91.4%; /* Input border */--ring:221.283.2%53.3%; /* Focus ring */--radius:0.5rem; /* Border radius */
}
.dark {
--background:222.284%4.9%;
--foreground:21040%98%;
--card:222.284%4.9%;
--card-foreground:21040%98%;
--popover:222.284%4.9%;
--popover-foreground:21040%98%;
--primary:217.291.2%59.8%;
--primary-foreground:222.284%4.9%;
--secondary:217.232.6%17.5%;
--secondary-foreground:21040%98%;
--muted:217.232.6%17.5%;
--muted-foreground:21520.2%65.1%;
--accent:217.232.6%17.5%;
--accent-foreground:21040%98%;
--destructive:062.8%30.6%;
--destructive-foreground:21040%98%;
--border:217.232.6%17.5%;
--input:217.232.6%17.5%;
--ring:224.376.3%94.1%;
}

Custom Styling

You can customize the appearance using the provided className props:

<Selectoptions={options}className="w-full max-w-md"// Container stylingtriggerClassName="border-2"// Trigger button styling dropdownClassName="shadow-2xl"// Dropdown stylingoptionClassName="hover:bg-blue-50"// Individual option styling/>

Responsive Design

The component is fully responsive and works well on all screen sizes:

<Selectoptions={options}size="sm"// Smaller on mobileclassName="w-full sm:w-64 md:w-80"// Responsive width/>

Performance

theReactSelect is optimized for performance with several built-in optimizations:

  • Debounced Search: Search input is debounced to prevent excessive filtering
  • Minimal Re-renders: Optimized state management to minimize unnecessary renders
  • Efficient Filtering: Fast client-side filtering with memoization
  • Lightweight Bundle: Small bundle size with tree-shaking support
  • Virtual Scrolling Ready: Can be extended with virtual scrolling for large datasets

Large Datasets

For very large datasets (1000+ options), consider:

// Use search to filter options<Selectoptions={largeDataset}searchablemaxHeight={200}placeholder="Search from 1000+ options..."/>// Or limit initial options and load moreconst[visibleOptions,setVisibleOptions]=useState(options.slice(0,100));

Migration Guide

From react-select

theReactSelect provides a similar API to react-select with some differences:

// react-selectimportSelectfrom'react-select';<Selectoptions={options}value={value}onChange={setValue}isMultiisSearchable/>// theReactSelectimport{Select}from'thereactselect';<Selectoptions={options}value={value}onValueChange={setValue}multiplesearchable/>

Key Differences

Featurereact-selecttheReactSelect
Multi-selectisMultimultiple
SearchisSearchablesearchable
Change handleronChangeonValueChange
ClearisClearableclearable
LoadingisLoadingloading
DisabledisDisableddisabled

Troubleshooting

Common Issues

Styling not appearing

Make sure you've included the required CSS variables in your global styles.

TypeScript errors

Ensure you're using the correct types:

import{Select,SelectOption}from'thereactselect';constoptions: SelectOption[]=[{value: 'apple',label: 'Apple'}];

Search not working

Ensure the searchable prop is set to true:

<Selectsearchableoptions={options}/>

Multi-select values not updating

Make sure you're using an array for multi-select values:

const[values,setValues]=useState<(string|number)[]>([]);<Selectmultiplevalue={values}onValueChange={setValues}options={options}/>

Browser Support

theReactSelect supports all modern browsers:

  • Chrome 60+
  • Firefox 60+
  • Safari 12+
  • Edge 79+

Accessibility

theReactSelect is built with accessibility as a core principle:

ARIA Support

  • role="combobox" for the main trigger
  • role="listbox" for the options container
  • role="option" for individual options
  • aria-expanded to indicate dropdown state
  • aria-selected for selected options
  • aria-disabled for disabled options
  • aria-label and aria-labelledby support

Keyboard Navigation

KeyAction
Arrow DownMove to next option
Arrow UpMove to previous option
EnterSelect highlighted option
SpaceSelect highlighted option
EscapeClose dropdown
TabMove focus to next element
HomeJump to first option
EndJump to last option

Screen Reader Support

  • Descriptive announcements for state changes
  • Clear labeling of all interactive elements
  • Proper focus management
  • Selection announcements

Visual Accessibility

  • High contrast mode support
  • Clear focus indicators
  • Sufficient color contrast ratios
  • Scalable text and UI elements

Implementation Tips

// Always provide descriptive labels<Selectoptions={options}placeholder="Choose your preferred fruit"aria-label="Fruit selection"/>// Use proper labeling for forms<labelhtmlFor="fruit-select">FavoriteFruit</label><Selectid="fruit-select"options={options}/>

Contributing

We welcome contributions! Please see our contributing guidelines:

Development Setup

# Clone the repository
git clone https://github.com/themrsami/thereactselect.git
cd thereactselect
# Install dependencies
npm install
# Start development server
npm run dev
# Build the library
npm run build:lib
# Run tests
npm test

Contribution Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Update documentation if needed
  7. Commit your changes (git commit -m 'Add amazing feature')
  8. Push to the branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

Code Style

  • Use TypeScript for all new code
  • Follow existing code formatting
  • Add JSDoc comments for public APIs
  • Include tests for new features
  • Update documentation as needed

Reporting Issues

When reporting issues, please include:

  • Clear description of the problem
  • Steps to reproduce
  • Expected vs actual behavior
  • Browser and version information
  • Code examples if applicable

Links

License

MIT © Usama

About

A beautiful, fast, and accessible React Select component library built with TypeScript and Tailwind CSS. Features multi-select with badges, search functionality, select all, dark mode support, keyboard navigation, and ARIA compliance. Zero dependencies except React. Published as thereactselect on npm.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages