bs-searchable-select
v1.0.0
Published
A searchable select dropdown component for Bootstrap 5 — zero framework dependencies.
Downloads
105
Maintainers
Readme
bs-searchable-select
A searchable select dropdown component for Bootstrap 5 — zero framework dependencies. Just include Bootstrap CSS, add the script, and go.
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
- 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 automatic Bootstrap theme integration
- Validation — Built-in
is-invalidsupport for Bootstrap form validation - Dark Mode — Inherits Bootstrap's
data-bs-themeautomatically - Accessible — ARIA
combobox/listboxroles, keyboard support
Installation
CDN (quickest)
<!-- CSS (after Bootstrap CSS) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bs-searchable-select@1/dist/bs-searchable-select.min.css">
<!-- JS (after Bootstrap JS, or standalone) -->
<script src="https://cdn.jsdelivr.net/npm/bs-searchable-select@1/dist/bs-searchable-select.min.js"></script>npm
npm install bs-searchable-select// ES module
import BsSearchableSelect from 'bs-searchable-select';
import 'bs-searchable-select/dist/bs-searchable-select.css';
// CommonJS
const BsSearchableSelect = require('bs-searchable-select');Manual
Copy dist/bs-searchable-select.min.js and dist/bs-searchable-select.min.css into your project and include them in your HTML.
Quick Start
JavaScript
<div id="my-select"></div>
<script>
var select = new BsSearchableSelect('#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 BsSearchableSelect(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 Bootstrap .is-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 BsSearchableSelect(...).
| 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 Bootstrap .is-invalid styling |
| dispose() | void | Tear down: unbind events, remove DOM, clean up |
Static Methods
| Method | Description |
|--------|-------------|
| BsSearchableSelect.initAll() | Initialise all [data-bss-toggle="searchable-select"] elements |
| BsSearchableSelect.getInstance(el) | Retrieve existing instance from a container element |
| BsSearchableSelect.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
});Examples
Custom Values
var select = new BsSearchableSelect('#el', {
options: myOptions,
allowCustomValue: true,
placeholder: 'Select or type…'
});
// Later:
select.getValue(); // the selected/typed value
select.isCustomValue(); // true if the user typed something not in the listInline Colour Styling
new BsSearchableSelect('#el', {
options: myOptions,
activeBackgroundColor: '#198754',
activeTextColor: '#fff',
inactiveBackgroundColor: '#f8f9fa',
inactiveTextColor: '#333'
});CSS Class Styling
new BsSearchableSelect('#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 BsSearchableSelect('#el', {
options: myOptions,
invalid: true
});
// Clear invalid when a value is selected
document.querySelector('#el').addEventListener('bss.change', function (e) {
if (e.detail.value) select.setInvalid(false);
});Non-Clearable
new BsSearchableSelect('#el', {
options: myOptions,
clearable: false
});Disabled State
var select = new BsSearchableSelect('#el', {
options: myOptions,
disabled: true,
value: 'banana'
});
// Toggle at runtime
select.enable();
select.disable();Dynamic Options
var select = new BsSearchableSelect('#el', {
options: []
});
// Fetch from API and populate
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 };
}));
});Bootstrap Theme Integration
The active item uses Bootstrap's --bs-primary CSS variable by default. If you customise $primary in your Bootstrap SCSS, the component picks it up automatically. The component also inherits Bootstrap's dark mode (data-bs-theme="dark") with no extra configuration.
Demo
Open index.html in a browser to see all features in action — no build step required.
# Or use a local server:
npx serve .Building
To generate minified dist files:
npm install
npm run buildThis produces:
dist/bs-searchable-select.js— unminified copydist/bs-searchable-select.min.js— minifieddist/bs-searchable-select.css— unminified copydist/bs-searchable-select.min.css— minified
License
MIT © Hussein Al Bayati
