Guide
Getting started
A select that enhances the <select> you already have: searchable, grouped, virtualised, and still the
control your form posts, validates and resets.
1. Install
npm install @devix-labs/select
Or, with no build step, load it from the CDN as an ES module:
<link rel="stylesheet" href="https://devix.pk/cdn/oss/select@1.0.0/select.min.css">
<script type="module">
import { createSelect } from 'https://devix.pk/cdn/oss/select@1.0.0/index.js';
createSelect(document.querySelector('#country'));
</script>
2. Enhance what is already there
<label for="country">Country</label>
<select id="country" name="country">
<option value="">Pick one</option>
<optgroup label="Gulf">
<option value="ae" data-description="+971" data-keywords="UAE|Emirates">United Arab Emirates</option>
<option value="sa" data-description="+966">Saudi Arabia</option>
</optgroup>
<optgroup label="Asia">
<option value="pk" data-description="+92" selected>Pakistan</option>
</optgroup>
</select>
import { createSelect } from '@devix-labs/select';
import '@devix-labs/select/styles.css';
const select = createSelect(document.querySelector('#country'), { searchable: true });
Everything the markup said is kept: labels, groups, disabled, selected, the leading empty option as
the placeholder, and data-description / data-keywords for the extras. The <select> stays in the
form, hidden, so FormData, form.reset(), native validation and server-rendered pages all behave as
they did before you added a line of JavaScript.
3. Or give it options in JavaScript
createSelect(document.querySelector('#user'), {
options: [
{ value: '1', label: 'Aisha Khan', description: 'aisha@example.com', group: 'Owners' },
{ value: '2', label: 'Bilal Ahmed', description: 'bilal@example.com', group: 'Editors' },
],
placeholder: 'Assign to…',
searchable: true,
clearable: true,
});
Without a <select> to enhance, pass name and the widget keeps a hidden input for the form.
4. Read and write it
select.getValue(); // 'pk' (an array when multiple)
select.setValue('ae');
select.getSelected(); // [{ value: 'ae', label: 'United Arab Emirates', … }]
select.setOptions(newList); // replace the list, keeping any still-valid selection
select.open(); select.close(); select.clear(); select.focus();
select.destroy(); // puts your <select> back exactly as it was
Events bubble from the widget's root, and the original control still fires input and change, so
form libraries that listen to it keep working:
element.addEventListener('dx:selectchange', (event) => console.log(event.detail.values));
What you get by default
- Search from the first keystroke, with accents, Arabic and Urdu spellings and non-ASCII digits folded, and the matched letters highlighted.
- Groups that stay with their matches instead of disappearing while you filter.
- A windowed list, so 100 000 options cost the same as 20.
- The top layer for the dropdown, so
overflow: hidden, modals and transforms can't clip it. - A bottom sheet on touch phones, with its own search box and thumb-sized rows.
- The APG combobox pattern: roles,
aria-activedescendant, type-ahead, Home/End/PageUp/PageDown. - Dark mode that follows the page.