Skip to content
Devix Open Source

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.
Updated 15 Sep 2026