A lightweight JavaScript library for custom HTML <select>
creation and managing.
No dependencies needed.
Base
Bootstrap
Control buttons
GSAP
jQuery
Mobile Touch Devices
Install with npm (recommended)
$ npm install --save custom-select
Or download the minified build file here. (jquery version is alternative, not needed!)
With ES6 modules via the import
statement:
import customSelect from 'custom-select';
In CommonJs environments with the require
function:
var customSelect = require("custom-select").default;
Note: the require().default
is necessary due to the babelify export system.
In HTML with the script
tag:
<script src="custom-select.min.js" type="text/javascript"></script>
and optionally:
<link rel="stylesheet" href="custom-select.css">
Start with a simple HTML <select>
:
<select id="mySelect">
<option value>Select...</option>
<option value="foo">Foo</option>
<option value="buz">Buz</option>
</select>
customSelect('select');
You can nest the select in their label
or you can use the for
attribute on the label.
Nested will work fine but it's formally wrong due to label element specification: only a select
element can be nested in a label
tag.
Here's the HTML result:
<div class="custom-select-container customSelect">
<span class="custom-select-opener" tabindex="0">
<span>Select...</span>
</span>
<select id="mySelect1">
<option value>Select...</option>
<option value="foo">Foo</option>
<option value="buz">Buz</option>
</select>
<div class="custom-select-panel">
<div class="custom-select-option is-selected has-focus" data-value="">Select...</div>
<div class="custom-select-option" data-value="foo">Foo</div>
<div class="custom-select-option" data-value="buz">Buz</div>
</div>
</div>
Also state classes will be added and removed while plugin working.
You can use default css included in plugin release or style it by yourself. You can also use advanced techniques for using native select on Mobile/touch devices. Check the examples for inspirations.
Array customSelect(elements[, pluginOptions]);
The elements parameter could be:
A DOMString selectors:
customSelect('.myForm .mySelect');
A instance of HTMLElement, tag SELECT:
customSelect(document.getElementById('mySelect'));
A list (NodeList, HTMLCollection, Array, etc) of instances of HTMLElement, tag SELECT:
customSelect(document.querySelector('.mySelect'));
//or
customSelect(document.getElementsByClassName('mySelect'));
The pluginOptions parameter is an object that overwrites some default plugin configurations.
The default config is:
{
containerClass: 'custom-select-container',
openerClass: 'custom-select-opener',
panelClass: 'custom-select-panel',
optionClass: 'custom-select-option',
optgroupClass: 'custom-select-optgroup',
isSelectedClass: 'is-selected',
hasFocusClass: 'has-focus',
isDisabledClass: 'is-disabled',
isOpenClass: 'is-open'
}
The return is an Array of customSelect instances, that contains all the public exposed methods and properties.
All css classes can be configured using pluginOptions, except container secondary class customSelect
which is only for internal use and should not be removed or used for styling purpose.
Self explained structure classes, and relative may-have status classes:
containerClass: 'custom-select-container'
may have isDisabledClass
, isOpenClass
openerClass: 'custom-select-opener'
panelClass: 'custom-select-panel'
optionClass: 'custom-select-option'
may have isSelectedClass
, hasFocusClass
optgroupClass: 'custom-select-optgroup'
isSelectedClass: 'is-selected'
- when the custom option is selected (as native selected attribute).
hasFocusClass: 'has-focus'
- when the custom option has current focus (mouseover, arrow navigation and keyboard autocomplete changes the focus).
isDisabledClass: 'is-disabled'
- when the select is disabled.
isOpenClass: 'is-open'
- when the panel is open.
Init return
const cstSel = customSelect('select')[0]; // return is an array of instances!
console.log(cstSel.open); // true|false
The DOM select
customSelect('select');
const cstSel = document.querySelector('select').customSelect
console.log(cstSel.open); // true|false
The DOM select container
customSelect('select');
const cstSel = document.querySelector('.customSelect').customSelect
console.log(cstSel.open); // true|false
Get the plugin options.
cstSel.pluginOptions;
Get/set property.
cstSel.open = true; // open the custom select
console.log(cstSel.open); // true
cstSel.open = false; // close the custom select
console.log(cstSel.open); // false
Get/set property.
cstSel.disabled = true; // disable the custom select
console.log(cstSel.disabled); // true
cstSel.disabled = false; // enable the custom select
console.log(cstSel.disabled); // false
Get/set property.
Change both the native select and the custom select. Use it just like nativeSelect.value
cstSel.value = 'foo'; // the first option with that value will be selected. If there is no option with that value the first one'll be selected.
console.log(cstSel.value); // return foo if there was an option with 'foo' value
Append an option or an optgroup to the select.
const option = document.createElement('option');
option.text = 'Foo';
option.value = 'bar';
cstSel.append(option);
The elements parameter could be:
An instance of HTMLElement, tag OPTION:
const toBeAppend = document.createElement('option');
An instance of HTMLElement, tag OPTGROUP:
const toBeAppend = document.createElement('optgroup');
A list (NodeList, HTMLCollection, Array, etc) of instance of HTMLElement, tag OPTION/OPTGROUP:
const toBeAppend = cstSel.empty();
The target parameter must be the select
(default) or an optgroup that is already inside the select.
insert an option or an optgroup before the specified target.
const option = document.createElement('option');
option.text = 'Foo';
option.value = 'foo';
const target = cstSel.select.options[2];
cstSel.insertBefore(option, target);
The elements parameter could be:
An instance of HTMLElement, tag OPTION:
const toBeAppend = document.createElement('option');
An instance of HTMLElement, tag OPTGROUP:
const toBeAppend = document.createElement('optgroup');
A list (NodeList, HTMLCollection, Array, etc) of instance of HTMLElement, tag OPTION/OPTGROUP:
const toBeAppend = cstSel.empty();
The target parameter must be an option
or an optgroup
that is already inside the select.
remove an option or an optgroup
cstSel.remove(cstSel.select.options[1]);
empty the select
cstSel.empty();
destroy the plugin, removing custom markup, classes, and listeners.
cstSel.destroy();
DOM Element
DOM Element
DOM Element
DOM Element
Only on container
.
cstSel.container.addEventListener('custom-select:open',
(e) => { console.log(`${e.target} is open 😊`)});
Only on container
.
cstSel.container.addEventListener('custom-select:close',
(e) => { console.log(`${e.target} is closed 😔`)});
Only on container
.
cstSel.container.addEventListener('custom-select:disabled',
(e) => { console.log(`${e.target} is disabled 👋`)});
Only on container
.
cstSel.container.addEventListener('custom-select:enabled',
(e) => { console.log(`${e.target} is enabled 👏`)});
Fired on custom option, recommended listener on panel
.
This CustomEvent
fires when the focused option moves outside the visible part of the panel
.
It bubbles, so the listener can be placed on every ancestor of the custom options.
This event is useful for custom animations on select's autocomplete-search, when the focus moves to the found option.
By default there's no animation but a simply scrollTop
change of the panel
.
You can overwrite this behaviour by simply adding an EventListener
, with useCapture
argument set to true
and an e.stopPropagation()
statement inside you listener's callback-function.
// Example with jQuery animate
cstSel.panel.addEventListener('custom-select:focus-outside-panel',
(e) => {
e.stopPropagation();
$(cstSel.panel).animate({
scrollTop: e.target.offsetTop,
}, 300)
}, true);
Only on select
.
cstSel.select.addEventListener('change',
(e) => { console.log(`${e.target} has changed it's value 👌`)});
If you really can't live without jQuery, an adaptor was made for you 😩: download jQuery version here.
$('#mySelect').customSelect();
$('#mySelect').customSelect('open', true);
$('#mySelect').customSelect('open');
$('#mySelect').customSelect('remove', $('#mySelect')[0].options[1]);
And now have fun ✌
Oh wait, I was almost forgetting:
- Chrome
- Safari 7.0
- Firefox 10 (maybe also older, but come on...)
- Android 4.0
- Mobile Safari 6.0
- Internet Explorer 10