@metadiv-studio/select-remote
v0.1.7
Published
A powerful, customizable remote data select component for React applications. This component provides a searchable dropdown that fetches options from remote APIs with built-in search functionality, custom rendering, and seamless integration with your exis
Downloads
77
Readme
@metadiv-studio/select-remote
A powerful, customizable remote data select component for React applications. This component provides a searchable dropdown that fetches options from remote APIs with built-in search functionality, custom rendering, and seamless integration with your existing UI components.
🚀 Installation
npm i @metadiv-studio/select-remote📖 Description
SelectRemote is a React component that creates a searchable dropdown select input that fetches data from remote APIs. It's designed to handle large datasets efficiently by implementing debounced search, remote data fetching, and customizable rendering options.
Key Features
- 🔍 Debounced Search: Built-in 500ms debouncing for optimal API performance
- 🌐 Remote Data Fetching: Fetch options from any API endpoint
- 🎨 Customizable Rendering: Custom render functions for labels and selected items
- ♿ Accessibility: Proper keyboard navigation and screen reader support
- 🎯 Portal-based Dropdown: Dropdown renders in a portal to avoid layout issues
- 🔄 Real-time Updates: Automatic refresh when dependencies change
- 🎭 Action Buttons: Optional action buttons for additional functionality
- 🌙 Dark Mode Support: Built-in dark mode styling with Tailwind CSS
🛠️ Usage
Basic Usage
import SelectRemote from '@metadiv-studio/select-remote';
function MyComponent() {
const [selectedValue, setSelectedValue] = useState('');
const fetchUsers = async (keyword: string) => {
const response = await fetch(`/api/users?search=${keyword}`);
return response.json();
};
const handleChange = (value: string, item?: User) => {
setSelectedValue(value);
console.log('Selected user:', item);
};
return (
<SelectRemote
value={selectedValue}
onChange={handleChange}
onList={fetchUsers}
renderLabel={(user) => user.name}
valueKey="id"
placeholder="Select a user"
/>
);
}Advanced Usage with Custom Rendering
import SelectRemote from '@metadiv-studio/select-remote';
function AdvancedSelect() {
const [selectedProduct, setSelectedProduct] = useState('');
const fetchProducts = async (keyword: string) => {
const response = await fetch(`/api/products?search=${keyword}`);
return response.json();
};
const getProduct = async (id: string) => {
const response = await fetch(`/api/products/${id}`);
return response.json();
};
const renderProductLabel = (product: Product) => (
<div className="flex items-center gap-2">
<img src={product.image} alt={product.name} className="w-6 h-6 rounded" />
<span>{product.name}</span>
<span className="text-gray-500">${product.price}</span>
</div>
);
const renderSelectedProduct = (product: Product) => (
<div className="flex items-center gap-2">
<img src={product.image} alt={product.name} className="w-4 h-4 rounded" />
<span className="font-medium">{product.name}</span>
</div>
);
return (
<SelectRemote
value={selectedProduct}
onChange={(value, product) => setSelectedProduct(value)}
onList={fetchProducts}
onGet={getProduct}
renderLabel={renderProductLabel}
renderSelectedItem={renderSelectedProduct}
valueKey="id"
placeholder="Choose a product"
className="w-80"
/>
);
}With Action Buttons
import SelectRemote from '@metadiv-studio/select-remote';
function SelectWithActions() {
const [selectedCategory, setSelectedCategory] = useState('');
const fetchCategories = async (keyword: string) => {
const response = await fetch(`/api/categories?search=${keyword}`);
return response.json();
};
const actionButtons = [
{
icon: 'plus',
onClick: () => console.log('Add new category'),
tooltip: 'Add Category'
},
{
icon: 'refresh',
onClick: () => console.log('Refresh categories'),
tooltip: 'Refresh'
}
];
return (
<SelectRemote
value={selectedCategory}
onChange={(value) => setSelectedCategory(value)}
onList={fetchCategories}
renderLabel={(category) => category.name}
valueKey="id"
placeholder="Select category"
actionButtons={actionButtons}
/>
);
}🔧 API Reference
Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| value | string | ✅ | Current selected value |
| onChange | (value: string, item?: T) => void | ✅ | Callback when selection changes |
| onList | (keyword: string) => Promise<AxiosResponse<Response<T[]>>> | ✅ | Function to fetch options list |
| onGet | (id: string, item?: T) => Promise<AxiosResponse<Response<T>>> | ❌ | Function to fetch single item |
| onListRef | any[] | ❌ | Dependencies array for refreshing options |
| renderSelectedItem | (item: T) => React.ReactNode | ❌ | Custom render for selected item |
| renderLabel | (item: T) => React.ReactNode | ✅ | Custom render for option labels |
| valueKey | keyof T | ✅ | Key to use as value from item object |
| placeholder | string | ❌ | Placeholder text when nothing is selected |
| disabled | boolean | ❌ | Whether the select is disabled |
| className | string | ❌ | Additional CSS classes |
| actionButtons | ActionButtonProps[] | ❌ | Optional action buttons |
Generic Type
The component is generic and accepts a type parameter T for your data structure:
interface User {
id: string;
name: string;
email: string;
}
<SelectRemote<User>
// ... props
/>🎨 Styling
The component uses Tailwind CSS classes and follows a consistent design system. Key styling features:
- Responsive Design: Adapts to container width
- Dark Mode: Automatic dark mode support
- Hover States: Interactive hover effects
- Focus States: Accessible focus indicators
- Custom Classes: Extensible via
classNameprop
Custom Styling
<SelectRemote
// ... other props
className="w-96 border-2 border-blue-500 rounded-lg"
/>🔄 Data Flow
- Initial Load: Component fetches initial options based on current value
- Search Input: User types in search box (debounced by 500ms)
- API Call:
onListfunction is called with search keyword - Options Update: Dropdown options are updated with API response
- Selection: User selects an option, triggering
onChangecallback - State Update: Component updates internal state and closes dropdown
🚨 Error Handling
The component includes built-in error handling:
- API errors are logged to console
- Graceful fallbacks for failed requests
- Empty state handling with user-friendly messages
🔌 Dependencies
This package has the following peer dependencies:
react^18react-dom^18
And includes these internal dependencies:
@metadiv-studio/action-buttons@metadiv-studio/axios-configurator@metadiv-studio/button@metadiv-studio/input@metadiv-studio/translation
📱 Browser Support
- Modern browsers with ES6+ support
- React 18+
- TypeScript support included
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
This project is licensed under the UNLICENSED license.
🆘 Support
If you encounter any issues or have questions, please open an issue on the GitHub repository.
