You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP โ†’
Socket
Book a DemoInstallSign in
Socket

multi-selector-dropdown

Package Overview
Dependencies
Maintainers
0
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

multi-selector-dropdown

A React component for multi-select dropdown with API-driven options, search capability, and add new option functionality

1.0.9
latest
Source
npmnpm
Version published
Weekly downloads
39
-91.54%
Maintainers
0
Weekly downloads
ย 
Created
Source

Multi-Selector Dropdown

A powerful React component for multi-select dropdown with API-driven options, search capability, and add new option functionality. Built with TypeScript and designed for modern React applications.

โœจ Features

  • ๐Ÿš€ API-Driven Options: Fetch options dynamically from external APIs
  • ๐Ÿ” Search Capability: Real-time search and filtering of options
  • โž• Add New Option: Add new values to the database if not found
  • ๐Ÿ“‹ Multi-Selection Support: Select multiple options simultaneously
  • โšก TypeScript Support: Full TypeScript support with type definitions
  • ๐ŸŽจ Customizable: Highly configurable with various props and callbacks
  • โ™ฟ Accessible: Built with accessibility in mind
  • ๐Ÿ›ก๏ธ Error Handling: Comprehensive error handling for API failures
  • ๐Ÿ“ฑ Responsive: Works seamlessly across different screen sizes
  • โšก Performance Optimized: Debounced search and efficient rendering
  • ๐ŸŽฏ Production Ready: Fully tested and ready for production use

๐Ÿ“ฆ Installation

npm install multi-selector-dropdown

๐Ÿ”ง Dependencies

This package requires the following peer dependencies:

npm install react react-dom react-bootstrap-typeahead

CSS Import

You'll also need to import the required CSS in your application:

import 'react-bootstrap-typeahead/css/Typeahead.css';

๐Ÿ“ธ Snapshot

multi-selector-dropdown-screenshot

๐Ÿš€ Basic Usage

A simple example showing the basic functionality of the component:

import { useState, useEffect } from 'react';
import { Typeahead } from 'react-bootstrap-typeahead';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'react-bootstrap-typeahead/css/Typeahead.css';
import './App.css'; // Assuming you have some custom styles

interface UserOption {
  id: string | number;
  label: string;
}

function App() {
  const [selectedOptions, setSelectedOptions] = useState<UserOption[]>([]);
  const [options, setOptions] = useState<UserOption[]>([]);

  useEffect(() => {
    const dummyUsers: UserOption[] = [
      { id: '1', label: 'Alice Johnson' },
      { id: '2', label: 'Bob Smith' },
      { id: '3', label: 'Charlie Davis' },
      { id: '4', label: 'Diana Ross' },
      { id: '5', label: 'Ethan Brown' },
    ];
    setOptions(dummyUsers);
  }, []);

  const handleAddNew = (value: string): UserOption => {
    const newUser = { id: `new-${Date.now()}`, label: value };
    setOptions((prev) => [...prev, newUser]);
    return newUser;
  };

  return (
    <div className="min-vh-100 d-flex align-items-center justify-content-center bg-light">
      <div className="container p-4 rounded-4 shadow-lg" style={{ maxWidth: '900px', backgroundColor: '#ffffff' }}>
        <h2 className="text-center text-primary fw-bold mb-4">Multi-Selector Dropdown</h2>
        <p className="text-center text-muted mb-5">
          This example uses hardcoded data instead of fetching from an API.
        </p>

        <div className="row justify-content-center">
          <div className="col-md-10">
            <label className="form-label text-dark fw-semibold">Select Users*</label>
            <Typeahead
              id="user-multi-select"
              labelKey="label"
              multiple
              allowNew
              newSelectionPrefix="Add new user: "
              options={options}
              placeholder="Search and select users..."
              onChange={(selected: any[]) => {
                const cleanOptions: UserOption[] = selected.map((item) =>
                  typeof item === 'string' ? handleAddNew(item) : item
                );
                setSelectedOptions(cleanOptions);
              }}
              selected={selectedOptions}
              className="bg-white rounded-3 shadow-sm border border-secondary"
            />
          </div>
        </div>

        {selectedOptions.length > 0 && (
          <div className="mt-5">
            <h4 className="text-dark text-center fw-semibold mb-4">Selected Users</h4>
            <div className="table-responsive">
              <table className="table table-striped table-hover table-bordered">
                <thead className="table-primary">
                  <tr>
                    <th>ID</th>
                    <th>Name</th>
                  </tr>
                </thead>
                <tbody>
                  {selectedOptions.map((option) => (
                    <tr key={option.id} className="align-middle">
                      <td>{option.id}</td>
                      <td>{option.label}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;

๐ŸŽฏ Advanced Usage

A comprehensive example demonstrating advanced features like multiple dropdowns, different configurations, and complex state management:

import React, { useState } from 'react';
import MultiSelectorDropdown from 'multi-selector-dropdown';
import { Option } from 'multi-selector-dropdown';
import 'react-bootstrap-typeahead/css/Typeahead.css';

const AdvancedExample = () => {
  const [selectedUsers, setSelectedUsers] = useState<Option[]>([]);
  const [selectedProducts, setSelectedProducts] = useState<Option[]>([]);
  const [selectedCategories, setSelectedCategories] = useState<Option[]>([]);

  // Mock API function for adding new users
  const handleAddNewUser = async (value: string): Promise<Option | null> => {
    await new Promise(resolve => setTimeout(resolve, 300));
    return {
      id: `user-${Date.now()}`,
      label: value,
      type: 'user'
    };
  };

  // Mock API function for adding new products
  const handleAddNewProduct = async (value: string): Promise<Option | null> => {
    await new Promise(resolve => setTimeout(resolve, 300));
    return {
      id: `product-${Date.now()}`,
      label: value,
      type: 'product'
    };
  };

  // Mock API function for adding new categories
  const handleAddNewCategory = async (value: string): Promise<Option | null> => {
    await new Promise(resolve => setTimeout(resolve, 300));
    return {
      id: `category-${Date.now()}`,
      label: value,
      type: 'category'
    };
  };

  const handleUserChange = (options: Option[]) => {
    setSelectedUsers(options);
    console.log('Selected users:', options);
  };

  const handleProductChange = (options: Option[]) => {
    setSelectedProducts(options);
    console.log('Selected products:', options);
  };

  const handleCategoryChange = (options: Option[]) => {
    setSelectedCategories(options);
    console.log('Selected categories:', options);
  };

  return (
    <div className="container mt-5">
      <h2>Multi-Selector Dropdown - Advanced Example</h2>
      <p className="text-muted">
        This example demonstrates advanced features including multiple dropdowns, 
        different configurations, and complex state management.
      </p>
      
      <div className="row">
        <div className="col-md-4">
          <h4>Users Dropdown</h4>
          <MultiSelectorDropdown
            apiUrl="https://jsonplaceholder.typicode.com/users"
            placeholder="Search and select users..."
            label="Select Users"
            required={true}
            allowAddNew={true}
            addNewPrefix="Add new user: "
            onAddNew={handleAddNewUser}
            onChange={handleUserChange}
            multiple={true}
            maxSelections={3}
            clearButton={true}
            size="sm"
            error=""
            touched={false}
          />
        </div>

        <div className="col-md-4">
          <h4>Products Dropdown</h4>
          <MultiSelectorDropdown
            apiUrl="https://jsonplaceholder.typicode.com/posts"
            placeholder="Search and select products..."
            label="Select Products"
            required={false}
            allowAddNew={true}
            addNewPrefix="Add new product: "
            onAddNew={handleAddNewProduct}
            onChange={handleProductChange}
            multiple={true}
            maxSelections={5}
            clearButton={true}
            size="md"
            error=""
            touched={false}
          />
        </div>

        <div className="col-md-4">
          <h4>Categories Dropdown</h4>
          <MultiSelectorDropdown
            apiUrl="https://jsonplaceholder.typicode.com/albums"
            placeholder="Search and select categories..."
            label="Select Categories"
            required={false}
            allowAddNew={true}
            addNewPrefix="Add new category: "
            onAddNew={handleAddNewCategory}
            onChange={handleCategoryChange}
            multiple={false}
            clearButton={true}
            size="lg"
            error=""
            touched={false}
          />
        </div>
      </div>

      <div className="row mt-4">
        <div className="col-md-4">
          <h5>Selected Users ({selectedUsers.length})</h5>
          <ul className="list-group">
            {selectedUsers.map((user) => (
              <li key={user.id} className="list-group-item">
                <strong>ID:</strong> {user.id} | <strong>Name:</strong> {user.label}
              </li>
            ))}
          </ul>
        </div>

        <div className="col-md-4">
          <h5>Selected Products ({selectedProducts.length})</h5>
          <ul className="list-group">
            {selectedProducts.map((product) => (
              <li key={product.id} className="list-group-item">
                <strong>ID:</strong> {product.id} | <strong>Name:</strong> {product.label}
              </li>
            ))}
          </ul>
        </div>

        <div className="col-md-4">
          <h5>Selected Categories ({selectedCategories.length})</h5>
          <ul className="list-group">
            {selectedCategories.map((category) => (
              <li key={category.id} className="list-group-item">
                <strong>ID:</strong> {category.id} | <strong>Name:</strong> {category.label}
              </li>
            ))}
          </ul>
        </div>
      </div>

      <div className="mt-4">
        <h4>Summary</h4>
        <div className="alert alert-info">
          <strong>Total Selected Items:</strong> {selectedUsers.length + selectedProducts.length + selectedCategories.length}
          <br />
          <strong>Users:</strong> {selectedUsers.length} | 
          <strong>Products:</strong> {selectedProducts.length} | 
          <strong>Categories:</strong> {selectedCategories.length}
        </div>
      </div>
    </div>
  );
};

export default AdvancedExample;

๐Ÿ”ง Recent Updates & Fixes

โœ… Version 1.0.3 - Production Ready

Major Improvements:

  • ๐Ÿ”ง Fixed Dropdown UI Issues: Improved styling and dropdown appearance
  • ๐ŸŽฏ Fixed Options Display: Options now appear correctly when clicking input field
  • โšก Enhanced Search Functionality: Real-time search with proper debouncing
  • ๐Ÿ› ๏ธ Improved Add New Feature: Better handling of custom option creation
  • ๐Ÿ“ฑ Better Mobile Support: Enhanced responsive design
  • ๐Ÿงช Comprehensive Testing: All tests passing (8/8)
  • ๐Ÿ“ฆ Build Optimization: Clean TypeScript compilation

Technical Fixes:

  • Fixed selected={[]} prop to ensure dropdown shows options
  • Improved filteredOptions logic for proper option filtering
  • Enhanced search term state management
  • Added proper error handling for API calls
  • Optimized component re-rendering
  • Fixed TypeScript type issues

API Reference

Props

PropTypeDefaultDescription
apiUrlstring-Required. The URL to fetch options from
apiMethod'GET' | 'POST''GET'HTTP method for API requests
apiHeadersRecord<string, string>{}Additional headers for API requests
apiParamsRecord<string, any>{}Additional parameters for API requests
placeholderstring'Select options...'Placeholder text for the input
labelstring-Label for the dropdown
requiredbooleanfalseWhether the field is required
disabledbooleanfalseWhether the dropdown is disabled
classNamestring''Additional CSS classes
searchEnabledbooleantrueEnable search functionality
searchPlaceholderstring-Placeholder for search input
minSearchLengthnumber0Minimum characters before triggering search
allowAddNewbooleantrueAllow adding new options
addNewPrefixstring'Add new: 'Prefix for new option suggestions
onAddNew(value: string) => Promise<Option | null>-Callback for adding new options
multiplebooleantrueEnable multi-selection
maxSelectionsnumber-Maximum number of selections allowed
onChange(selectedOptions: Option[]) => void-Callback when selection changes
onSearch(searchTerm: string) => void-Callback when search term changes
onBlur() => void-Callback when input loses focus
onFocus() => void-Callback when input gains focus
valueOption[][]Controlled value
defaultValueOption[][]Default value
clearButtonbooleantrueShow clear button
size'sm' | 'md' | 'lg''md'Size of the dropdown
errorstring-Error message to display
touchedbooleanfalseWhether the field has been touched

Types

Option

interface Option {
  id: string | number;
  label: string;
  [key: string]: any;
}

ApiResponse

interface ApiResponse<T> {
  data: T[];
  total?: number;
  page?: number;
  limit?: number;
  [key: string]: any;
}

API Response Format

The component expects the API to return data in one of these formats:

Array Format

[
  { "id": 1, "label": "Option 1" },
  { "id": 2, "label": "Option 2" }
]

Object Format

{
  "data": [
    { "id": 1, "label": "Option 1" },
    { "id": 2, "label": "Option 2" }
  ],
  "total": 2,
  "page": 1,
  "limit": 10
}

Styling

The component uses Bootstrap classes by default. You can customize the styling by:

  • Overriding CSS classes
  • Using the className prop
  • Customizing the Bootstrap theme

Custom CSS Example

.multi-selector-dropdown .rbt-input-main {
  border-radius: 0.375rem;
}

.multi-selector-dropdown .btn-outline {
  border-radius: 50px;
}

.multi-selector-dropdown .checkbox-pill {
  background-color: #007bff;
  border-color: #007bff;
}

Error Handling

The component includes built-in error handling for:

  • API request failures
  • Network errors
  • Invalid responses
  • Add new option failures

Errors are logged to the console and can be handled through the onAddNew callback.

Accessibility

The component is built with accessibility in mind:

  • Proper ARIA labels
  • Keyboard navigation support
  • Screen reader compatibility
  • Focus management

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Testing

The component includes comprehensive tests:

npm test

All tests are passing and cover:

  • Component rendering
  • API integration
  • Search functionality
  • Add new option feature
  • Multi-selection behavior
  • Error handling

Development

Local Testing

# Build the package
npm run build

# Run tests
npm test

# Link for local development
npm link

Publishing

# Build and publish
npm run build
npm publish

License

MIT

Contributing

  • Fork the repository
  • Create a feature branch
  • Make your changes
  • Add tests
  • Submit a pull request

๐Ÿ’ก Contributing

Pull requests and issues are welcome! Please open an issue or PR on GitHub.

๐Ÿ‘ค Author

Akshay Bhalala
akshaybhalala@gmail.com

๐Ÿค Contributing

We welcome contributions! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

๐Ÿ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ”‘ Keywords

  • react
  • dropdown
  • multi-select
  • typeahead
  • search
  • api
  • typescript
  • bootstrap
  • form-control
  • autocomplete
  • select
  • input
  • ui-component
  • react-component
  • javascript
  • frontend
  • web-development
  • user-interface
  • interactive
  • responsive

Keywords

react

FAQs

Package last updated on 28 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts