braesident / dropdown
Dropdown for Bootstrap
Package info
github.com/braesident/Dropdown
Language:JavaScript
Type:extension
pkg:composer/braesident/dropdown
1.0.6
2026-03-02 08:39 UTC
README
This extension wraps a Bootstrap dropdown into a reusable JavaScript class (Dropdown) and adds:
- a searchable dropdown input
- a hidden input for stable form values
- dynamic item loading/replacement
- programmatic selection and reset
- optional swipe actions per item
- optional List.js integration
Purpose and Use Cases
Use this when a plain Bootstrap dropdown is not enough, for example:
- large selectable lists with live filtering
- forms that must submit a stable value (
key) through a hidden field - dynamic data sources (Ajax/reload) without rebuilding markup manually
- extra interactions such as swipe delete or preselection
Requirements
- Bootstrap 5 (or 4 via the built-in
window.bs4fallback) - jQuery (used internally)
- optional: List.js when using
listjs: true
Quick Start
HTML:
<div id="countryDropdown"></div>
JavaScript:
const dd = new Dropdown('countryDropdown', { placeholder: 'Select country', items: { de: { description: 'Germany' }, at: { description: 'Austria' }, ch: { description: 'Switzerland' } }, onSelected: () => { const selected = dd.selected(); console.log('Selected:', selected?.key, selected?.description); } });
The selected value is stored in the hidden input with name="countryDropdown".
Initialization: Full Options List
const dd = new Dropdown('exampleDropdown', { bootstrapmajor: 5, buttonstyle: 'btn-outline-secondary', caret: true, disabled: false, floatingbox: false, items: {}, listjs: false, filter: true, menumaxheight: '300px', menustyle: '', placeholder: '', required: false, swipe: { left: { hint: false, action: false, condition: (idx, item, li) => true }, right: { hint: false, action: false, condition: (idx, item, li) => true } }, onSelected: e => {}, onInput: (event, input) => {}, onReplaceText: undefined, item: '<li>Entry</li>', valueNames: [], valueKey: undefined, bootstrapAutoClose: undefined });
| Option | Type | Default | Description |
|---|---|---|---|
bootstrapmajor |
number |
5 |
Bootstrap major version (5 or 4). |
buttonstyle |
string |
'btn-outline-secondary' |
Extra classes on the toggle button. |
caret |
boolean |
true |
Shows/hides the caret on the button (false disables it). |
disabled |
boolean |
false |
Disables input, toggle, and hidden input. |
floatingbox |
boolean |
false |
Enables Bootstrap floating-label behavior (with filter: true). |
items |
object |
{} |
Initial entries. Keys become data-value / hidden-input value. |
listjs |
boolean |
false |
Enables List.js mode instead of native menu rendering. |
filter |
boolean |
true |
Enables/disables searchable input (false = button label only). |
menumaxheight |
string |
'300px' |
Menu max-height (inline style). |
menustyle |
string |
'' |
Additional inline style for the menu. |
placeholder |
string |
'' |
Placeholder for search input or label placeholder when filter: false. |
required |
boolean |
false |
Sets required on the search input. |
swipe.left.hint |
string|false |
false |
HTML hint for left swipe (for example an icon). |
swipe.left.action |
function|false |
false |
Callback on valid left swipe ((event, li) => {}). |
swipe.left.condition |
function |
(item) => true |
Condition to allow left swipe ((idx, item, li) => boolean). |
swipe.right.hint |
string|false |
false |
HTML hint for right swipe. |
swipe.right.action |
function|false |
false |
Callback on valid right swipe ((event, li) => {}). |
swipe.right.condition |
function |
(item) => true |
Condition to allow right swipe ((idx, item, li) => boolean). |
onSelected |
function |
(e) => {} |
Runs after an item is selected. |
onInput |
function |
(event, input) => {} |
Runs while typing/filtering. |
onReplaceText |
function|undefined |
undefined |
Overrides default display-text replacement (click/focusout). |
item |
string |
'<li>Entry</li>' |
List.js item template (listjs: true). |
valueNames |
array |
[] |
List.js field definitions (listjs: true). |
valueKey |
string|undefined |
auto |
Forces which List.js item field is used as internal key. |
bootstrapAutoClose |
boolean|undefined |
undefined |
Relevant only for Bootstrap 4 fallback; false prevents hide.bs.dropdown. |
Item Structure
A single items entry currently supports:
items: { de: { description: 'Germany', // string | Element | { short, extended } disabled: false, // optional active: false, // optional, marks item as active/preselected selected: false, // optional dataList: { // optional extra attributes for item button 'data-country-code': 'DE' } } }
Usage Snippets
1. Set items dynamically
dd.setItems({ fr: { description: 'France' }, it: { description: 'Italy' } });
2. Select programmatically
await dd.selected('it'); // triggers click on item with key "it"
3. Clear selection / input
dd.clear({ resetSelection: true, resetInput: true, close: true });
4. Disable/enable dropdown
dd.setDisabled(true); // disable dd.setDisabled(false); // enable
5. Swipe action on list entries
const taskDd = new Dropdown('taskDropdown', { items: { 1: { description: 'Task A' }, 2: { description: 'Task B' } }, swipe: { left: { hint: '<i class="bi bi-trash"></i>', action: (event, li) => { console.log('Delete:', li); return true; // true => entry is removed with animation } } } });
6. Dispose cleanly (for example before DOM removal)
dd.dispose();
Important Methods (Short Overview)
setItems(items, callback?, options?): add new entries / re-renderselected(): get currently selected itemselected(key): select item by keyselected(null): clear current selectionclear(options?): clear items/selection in a controlled waysetDisabled(state): enable/disable interactiongetInput(): current visible input textmatchItem(): number of exact matches for current inputdispose(): remove listeners/instance safely
Notes
- With
filter: false, the component uses a button label instead of a search input. - When
listjs: true, List.js must be available, otherwise initialization is incomplete. - The container dispatches custom events including
dropdown-items-rendered.