selectamelo
v0.1.2
Published
Vanilla JS select enhancer core (no framework integration)
Maintainers
Readme
Selectamelo
selectamelo is a vanilla JavaScript component that enhances a standard
HTML <select> element (single or multiple) into a modern, accessible and dynamic select.
It does not use jQuery, does not depend on UI frameworks, and keeps the original<select> in the DOM to preserve native form submission and backend compatibility.
Features
- Single and multiple select
- Built-in search
- Clear button (X)
- Multiple select with removable chips
- Full keyboard navigation (↑ ↓ Enter Esc Tab Backspace)
- Dynamic option management
- Native HTML
disabled - Simulated
readonly(non-editable but still submitted) - Custom events (
zselect:*) - 100% Vanilla JS
Installation
NPM
npm install selectameloBuild (package development only)
npm run buildBasic usage
HTML
<select id="role">
<option value=""></option>
<option value="admin">Admin</option>
<option value="editor">Editor</option>
</select>JavaScript (ESM)
import { Selectamelo } from "selectamelo";
const select = document.querySelector("#role");
Selectamelo.create(select, {
placeholder: "Select a role"
});Options
type SelectameloOptions = {
searchable?: boolean; // default true
placeholder?: string; // default ""
allowClear?: boolean; // default true
hideSearch?: boolean; // default false
disabled?: boolean; // disables the select (NOT submitted)
readonly?: boolean; // locks UI but value is submitted
};disabled vs readonly
| State | Interaction | Submit | |----------|-------------|--------| | disabled | ❌ | ❌ | | readonly | ❌ | ✅ |
HTML-driven options are also supported:
<select
data-allow-clear="true"
data-hide-search="true"
data-searchable="false"
data-readonly="true"
></select>Instance API
Create / Get
const inst = Selectamelo.create(select);
const same = Selectamelo.get(select);Value
inst.getValue(); // string | string[]
inst.setValue("admin"); // single
inst.setValue(["1","2"]); // multiple
inst.setValue(null); // resetOpen / Close
inst.open();
inst.close();State
inst.setDisabled(true);
inst.setDisabled(false);
inst.setReadonly(true);
inst.setReadonly(false);
inst.isDisabled(); // boolean
inst.isReadonly(); // booleanLoading
Temporarily blocks UI interaction.
inst.setLoading(true);
inst.setLoading(false);Dynamic option management
Clear options
inst.clearOptions(true); // keep placeholderSet a full option list
inst.setOptions(
[
{ value: "1", label: "Rome" },
{ value: "2", label: "Tivoli", disabled: true }
],
true
);Add an option
inst.addOption({ value: "3", label: "Latina" });Add and select
inst.addOption({ value: "3", label: "Latina" }, true);Remove an option
inst.removeOption("2");Update an option
inst.updateOption("1", { label: "Rome (RM)" });
inst.updateOption("2", { disabled: false });Upsert (create or update)
inst.upsertOption({ value: "9", label: "Frosinone" });
inst.upsertOption({ value: "9", label: "Frosinone (FR)" });Custom events
Events are emitted on the original <select> element.
select.addEventListener("zselect:change", e => {
console.log(e.detail.value);
});Available events
| Event | Description |
|------------------|-------------|
| zselect:open | Dropdown opened |
| zselect:close | Dropdown closed |
| zselect:search | Search input (detail.q) |
| zselect:clear | Value cleared |
| zselect:change | Value changed |
Common pattern: dependent selects
province.addEventListener("change", () => {
cityInst.setOptions(
[...province.selectedOptions].map(o => ({
value: o.value,
label: o.textContent.trim()
}))
);
});Philosophy
- No dependencies
- No frameworks
- DOM as the source of truth
- Core-only and framework-agnostic
- Optional adapters/wrappers
License
MIT © Zycon
