Skip to content

Instantly share code, notes, and snippets.

@croxton
Created October 13, 2025 07:43
Show Gist options
  • Select an option

  • Save croxton/6c4028fce4a9e744e6f49c720bdabf6b to your computer and use it in GitHub Desktop.

Select an option

Save croxton/6c4028fce4a9e744e6f49c720bdabf6b to your computer and use it in GitHub Desktop.
Vanilla Multi Select for htmx Booster Pack
/**
* Multi Select
*
* Enhances <select multiple>
*/
import {Booster} from 'htmx-booster-pack';
import { multipleSelect } from 'multiple-select-vanilla';
import 'multiple-select-vanilla/dist/styles/css/multiple-select.css';
export default class MultiSelect extends Booster {
ms = null;
dirty = false;
constructor(elm) {
super(elm);
this.mount();
}
mount() {
const elmMount = document.querySelector(this.elm);
const form = elmMount.closest('form');
const submitBtn = form.querySelector('button[type="submit"]');
const label = elmMount.querySelector('label').textContent;
this.options = {
"showFilter": "false"
};
const isMultiple = document.querySelector(this.elm + '> select').getAttribute('multiple') === 'multiple';
this.ms = multipleSelect(this.elm + '> select', {
selectAll: false,
filter: (this.options.showFilter === 'true'),
filterPlaceholder: 'Search…',
minimumCountSelected:0,
renderOptionLabelAsHtml: true,
showOkButton: true,
placeholder: label,
maxHeight: 252,
formatCountSelected(count, total) {
if (isMultiple) {
return `${label} (${count})`;
}
},
formatAllSelected() {
if (isMultiple) {
return `${label} (All)`;
}
},
formatOkButton() {
return 'Update';
},
onClick: () => {
this.dirty = true;
elmMount.classList.add('is-dirty');
},
onClose: (reason) => {
if (this.dirty) {
this.dirty = false;
elmMount.classList.remove('is-dirty');
this.ms.focus();
form.dispatchEvent(new CustomEvent("updateResults"));
}
}
});
}
unmount() {
this.ms?.destroy();
this.ms = null; // remove detached element
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment