@h7o/searchable-select
v1.0.0
Published
A framework-agnostic searchable select dropdown component — zero dependencies. Self-contained JS + CSS that works anywhere.
Downloads
54
Maintainers
Readme
searchable-select
A framework-agnostic searchable select dropdown — zero dependencies. No Bootstrap, no React, no jQuery. Self-contained JS + CSS that works anywhere.
Part of the SearchableSelect family:
searchable-select— Framework-agnostic (this package)bs-searchable-select— Bootstrap 5react-bs-searchable-select— React + Bootstrap
Features
- Search & Filter — Case-insensitive substring matching across all option labels
- Custom Values — Optionally allow users to type values not in the list
- Clearable — One-click clear button (can be disabled)
- Keyboard Navigation — Arrow keys, Enter to select, Escape to close, Tab to close
- Programmatic API —
getValue(),setValue(),addOption(),removeOption(),clearSelection(), and more - Data-Attribute Init — Configure entirely in HTML with
data-bss-*attributes - Custom Events —
bss.change,bss.show,bss.hide,bss.clearon the container element - Styling — Inline colour props, CSS class overrides, or CSS custom properties (variables)
- Validation — Built-in
.bss-invalidsupport for form validation - Dark Mode —
data-bss-theme="dark",bss-darkclass, or Bootstrap'sdata-bs-theme="dark" - Theming — Full control via CSS custom properties — colours, borders, fonts, radii, shadows
- Accessible — ARIA
combobox/listboxroles, keyboard support - Zero Dependencies — Ships its own complete CSS, works in any environment
- UMD Module — Works with
<script>tags, CommonJS (require), and AMD (define) - ES5 Compatible — No transpilation needed, works in older browsers
Installation
CDN (quickest)
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/searchable-select@1/dist/searchable-select.min.css">
<!-- JS -->
<script src="https://cdn.jsdelivr.net/npm/searchable-select@1/dist/searchable-select.min.js"></script>npm
npm install searchable-select// ES module
import SearchableSelect from 'searchable-select';
import 'searchable-select/dist/searchable-select.css';
// CommonJS
const SearchableSelect = require('searchable-select');Manual
Copy dist/searchable-select.min.js and dist/searchable-select.min.css into your project and include them in your HTML.
Quick Start
JavaScript
<link rel="stylesheet" href="searchable-select.min.css">
<script src="searchable-select.min.js"></script>
<div id="my-select"></div>
<script>
var select = new SearchableSelect('#my-select', {
options: [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'cherry', label: 'Cherry' }
],
placeholder: 'Select a fruit...',
onChange: function (value, option) {
console.log('Selected:', value);
}
});
</script>Data Attributes (no JS required)
<div data-bss-toggle="searchable-select"
data-bss-placeholder="Pick a fruit..."
data-bss-options='[
{"value":"apple","label":"Apple"},
{"value":"banana","label":"Banana"},
{"value":"cherry","label":"Cherry"}
]'>
</div>Elements with data-bss-toggle="searchable-select" are automatically initialised on DOMContentLoaded. Listen for events via the DOM:
document.getElementById('my-select')
.addEventListener('bss.change', function (e) {
console.log('Selected:', e.detail.value);
});Configuration
Pass these as the second argument to new SearchableSelect(el, config), or as data-bss-* attributes in HTML.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| options | Array<{ value, label }> | [] | Array of selectable options |
| value | any | null | Initially selected value |
| placeholder | string | 'Select...' | Placeholder text |
| maxDropdownHeight | number | 200 | Max dropdown height in pixels |
| allowCustomValue | boolean | false | Allow values not in the options list |
| disabled | boolean | false | Disable the component |
| clearable | boolean | true | Show/hide the clear (×) button |
| invalid | boolean | false | Apply .bss-invalid styling |
| activeBackgroundColor | string | — | Background colour of the selected item |
| activeTextColor | string | — | Text colour of the selected item |
| activeClassName | string | — | CSS class for the selected item (overrides inline styles) |
| inactiveBackgroundColor | string | — | Background colour for unselected items |
| inactiveTextColor | string | — | Text colour for unselected items |
| inactiveClassName | string | — | CSS class for unselected items (overrides inline styles) |
| onChange | function(value, option) | — | Callback on selection change; receives (null, null) on clear |
Data-attribute mapping
Prefix every option with data-bss- and use kebab-case:
<div data-bss-toggle="searchable-select"
data-bss-placeholder="Pick…"
data-bss-allow-custom-value="true"
data-bss-clearable="false"
data-bss-max-dropdown-height="300"
data-bss-options='[{"value":"a","label":"A"}]'>
</div>Methods
All methods are available on the instance returned by new SearchableSelect(...).
| Method | Returns | Description |
|--------|---------|-------------|
| getValue() | any | Current value (selected option value or custom text) |
| setValue(value) | void | Programmatically select a value |
| isCustomValue() | boolean | true if the current value is not from the options list |
| getInputText() | string | Raw text currently shown in the input |
| clearSelection() | void | Clear the selection |
| addOption({ value, label }) | void | Add an option (duplicates ignored) |
| removeOption(value) | void | Remove an option; clears selection if it was active |
| setOptions(options) | void | Replace the entire options list |
| getOptions() | Array | Get a copy of the current options list |
| enable() | void | Enable the component |
| disable() | void | Disable the component |
| setInvalid(bool) | void | Toggle .bss-invalid styling |
| dispose() | void | Tear down: unbind events, remove DOM, clean up |
Static Methods
| Method | Description |
|--------|-------------|
| SearchableSelect.initAll() | Initialise all [data-bss-toggle="searchable-select"] elements |
| SearchableSelect.getInstance(el) | Retrieve existing instance from a container element |
| SearchableSelect.fromDataAttributes(el) | Create instance from an element's data-bss-* attributes |
Events
Custom DOM events are dispatched on the container element:
| Event | e.detail | Description |
|-------|------------|-------------|
| bss.change | { value, option } | Selection changed |
| bss.show | {} | Dropdown opened |
| bss.hide | {} | Dropdown closed |
| bss.clear | {} | Selection cleared |
document.querySelector('#my-select')
.addEventListener('bss.change', function (e) {
console.log('New value:', e.detail.value);
console.log('Option object:', e.detail.option); // null if custom
});Theming with CSS Custom Properties
Every visual aspect can be customised via CSS variables on .bss-container:
.bss-container {
/* Input */
--bss-input-bg: #fff;
--bss-input-color: #212529;
--bss-input-border: #ced4da;
--bss-input-border-radius: 0.375rem;
--bss-input-focus-border: #86b7fe;
--bss-input-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
--bss-input-placeholder-color: #6c757d;
/* Dropdown */
--bss-dropdown-bg: #fff;
--bss-dropdown-border: #dee2e6;
--bss-dropdown-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
--bss-dropdown-radius: 0.375rem;
/* Options */
--bss-option-active-bg: #0d6efd;
--bss-option-active-color: #fff;
--bss-option-hover-bg: #f8f9fa;
--bss-option-focused-bg: #e9ecef;
/* Typography */
--bss-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--bss-font-size: 0.9375rem;
}Dark Mode
Enable dark mode in any of these ways:
<!-- On any ancestor element -->
<html data-bss-theme="dark">
<!-- On the container itself -->
<div id="select" class="bss-dark"></div>
<!-- Also works with Bootstrap's data-bs-theme -->
<html data-bs-theme="dark">Migrating from Chosen
If you're replacing the jQuery Chosen plugin:
- Remove Chosen JS and CSS files
- Include
searchable-select.min.jsandsearchable-select.min.css - Replace
<select>elements with<div>containers - Initialise with
new SearchableSelect(el, { options: [...] }) - Replace Chosen events with
bss.change,bss.show,bss.hide
// Before (Chosen)
$('#my-select').chosen({ allow_single_deselect: true });
$('#my-select').on('change', function () { ... });
// After (SearchableSelect)
var select = new SearchableSelect('#my-select', {
options: [...],
clearable: true,
onChange: function (value) { ... }
});Migrating from bs-searchable-select
The API is identical — just change the constructor name:
// Before
var select = new BsSearchableSelect('#el', config);
// After
var select = new SearchableSelect('#el', config);Both use the same bss- CSS prefix, same data attributes, same events, and same methods.
Examples
Custom Values
var select = new SearchableSelect('#el', {
options: myOptions,
allowCustomValue: true,
placeholder: 'Select or type…'
});
select.getValue(); // the selected/typed value
select.isCustomValue(); // true if typed something not in the listInline Colour Styling
new SearchableSelect('#el', {
options: myOptions,
activeBackgroundColor: '#198754',
activeTextColor: '#fff',
inactiveBackgroundColor: '#f8f9fa',
inactiveTextColor: '#333'
});CSS Class Styling
new SearchableSelect('#el', {
options: myOptions,
activeClassName: 'my-active',
inactiveClassName: 'my-inactive'
});.my-active {
background-color: #6f42c1 !important;
color: #fff !important;
border-left: 3px solid #4a2a8a;
}
.my-inactive:hover {
background-color: #e9ecef;
}Form Validation
var select = new SearchableSelect('#el', {
options: myOptions,
invalid: true
});
document.querySelector('#el').addEventListener('bss.change', function (e) {
if (e.detail.value) select.setInvalid(false);
});Dynamic Options
var select = new SearchableSelect('#el', { options: [] });
fetch('/api/items')
.then(function (r) { return r.json(); })
.then(function (data) {
select.setOptions(data.map(function (d) {
return { value: d.id, label: d.name };
}));
});Demo
Open index.html in a browser to see all features in action — no build step required, no CDN dependencies.
npx serve .Building
To generate minified dist files:
npm install
npm run buildThis produces:
dist/searchable-select.js— unminified copydist/searchable-select.min.js— minifieddist/searchable-select.css— unminified copydist/searchable-select.min.css— minified
License
MIT © Hussein Al Bayati
