In this guide, we shall enhance the capabilities of the native select element with selectable options, search functionality, customizable items, and last but not least, a much better UI design. We'll mimic the native HTML select element and utilize JS classes to provide a user-friendly dropdown box with checkboxes.
The multi-select dropdown JS class will enable users to select multiple options within an elegant dropdown list with additional functions such as searching, selecting all options, and limiting the maximum number of items the user can select. To do that, we can leverage JavaScript, HTML, and CSS3.
One of the advantages of using a preexisting HTML form element is that the class will fall back to the original element if JavaScript is disabled in the user's browser, and therefore, the user can still interact with the form element. Not only that, but the entire class is written in pure JS, so we don't have to include additional libraries such as jQuery — why use jQuery when we can leverage ES6+.
So, without further ado, let's get started!
Contents
1. Stylesheet (CSS3)
The stylesheet will be responsible for our multi-select dropdown element's UI design and structure. We can leverage CSS3 to create a modernized appearance.
Create a new file called MultiSelect.css and add the following CSS code:
.multi-select {
display: flex;
box-sizing: border-box;
flex-direction: column;
position: relative;
width: 100%;
user-select: none;
}
.multi-select .multi-select-header {
border: 1px solid #dee2e6;
padding: 7px 30px 7px 12px;
overflow: hidden;
gap: 7px;
min-height: 45px;
}
.multi-select .multi-select-header::after {
content: "";
display: block;
position: absolute;
top: 50%;
right: 15px;
transform: translateY(-50%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23949ba3' viewBox='0 0 16 16'%3E%3Cpath d='M8 13.1l-8-8 2.1-2.2 5.9 5.9 5.9-5.9 2.1 2.2z'/%3E%3C/svg%3E");
height: 12px;
width: 12px;
}
.multi-select .multi-select-header.multi-select-header-active {
border-color: #c1c9d0;
}
.multi-select .multi-select-header.multi-select-header-active::after {
transform: translateY(-50%) rotate(180deg);
}
.multi-select .multi-select-header.multi-select-header-active + .multi-select-options {
display: flex;
}
.multi-select .multi-select-header .multi-select-header-placeholder {
color: #65727e;
}
.multi-select .multi-select-header .multi-select-header-option {
display: inline-flex;
align-items: center;
background-color: #f3f4f7;
font-size: 14px;
padding: 3px 8px;
border-radius: 5px;
}
.multi-select .multi-select-header .multi-select-header-max {
font-size: 14px;
color: #65727e;
}
.multi-select .multi-select-options {
display: none;
box-sizing: border-box;
flex-flow: wrap;
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 999;
margin-top: 5px;
padding: 5px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
}
.multi-select .multi-select-options::-webkit-scrollbar {
width: 5px;
}
.multi-select .multi-select-options::-webkit-scrollbar-track {
background: #f0f1f3;
}
.multi-select .multi-select-options::-webkit-scrollbar-thumb {
background: #cdcfd1;
}
.multi-select .multi-select-options::-webkit-scrollbar-thumb:hover {
background: #b2b6b9;
}
.multi-select .multi-select-options .multi-select-option, .multi-select .multi-select-options .multi-select-all {
padding: 4px 12px;
height: 42px;
}
.multi-select .multi-select-options .multi-select-option .multi-select-option-radio, .multi-select .multi-select-options .multi-select-all .multi-select-option-radio {
margin-right: 14px;
height: 16px;
width: 16px;
border: 1px solid #ced4da;
border-radius: 4px;
}
.multi-select .multi-select-options .multi-select-option .multi-select-option-text, .multi-select .multi-select-options .multi-select-all .multi-select-option-text {
box-sizing: border-box;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: inherit;
font-size: 16px;
line-height: 20px;
}
.multi-select .multi-select-options .multi-select-option.multi-select-selected .multi-select-option-radio, .multi-select .multi-select-options .multi-select-all.multi-select-selected .multi-select-option-radio {
border-color: #40c979;
background-color: #40c979;
}
.multi-select .multi-select-options .multi-select-option.multi-select-selected .multi-select-option-radio::after, .multi-select .multi-select-options .multi-select-all.multi-select-selected .multi-select-option-radio::after {
content: "";
display: block;
width: 3px;
height: 7px;
margin: 0.12em 0 0 0.27em;
border: solid #fff;
border-width: 0 0.15em 0.15em 0;
transform: rotate(45deg);
}
.multi-select .multi-select-options .multi-select-option.multi-select-selected .multi-select-option-text, .multi-select .multi-select-options .multi-select-all.multi-select-selected .multi-select-option-text {
color: #40c979;
}
.multi-select .multi-select-options .multi-select-option:hover, .multi-select .multi-select-options .multi-select-option:active, .multi-select .multi-select-options .multi-select-all:hover, .multi-select .multi-select-options .multi-select-all:active {
background-color: #f3f4f7;
}
.multi-select .multi-select-options .multi-select-all {
border-bottom: 1px solid #f1f3f5;
border-radius: 0;
}
.multi-select .multi-select-options .multi-select-search {
padding: 7px 10px;
border: 1px solid #dee2e6;
border-radius: 5px;
margin: 10px 10px 5px 10px;
width: 100%;
outline: none;
font-size: 16px;
}
.multi-select .multi-select-options .multi-select-search::placeholder {
color: #b2b5b9;
}
.multi-select .multi-select-header, .multi-select .multi-select-option, .multi-select .multi-select-all {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
align-items: center;
border-radius: 5px;
cursor: pointer;
display: flex;
align-items: center;
width: 100%;
font-size: 16px;
color: #212529;
}
That's essentially all we need to present our multi-select dropdown element. You're welcome to customize the properties, such as the border color, font size, etc, to reflect your site's design.
We can include the stylesheet in our <head> section with the following tag:
<link href="MultiSelect.css" rel="stylesheet" type="text/css">
But we'll get more on that later in the examples section.
2. JavaScript Class
The JavaScript class includes a bunch of methods that replace the native select element with a much more customizable one. In addition to that, we can bind event handlers, configure options, and specify data while creating a new instance of the class.
Create a new file called MultiSelect.js and add the following code:
/*
* Created by David Adams
* https://codeshack.io/multi-select-dropdown-html-javascript/
*
* Released under the MIT license
*/
class MultiSelect {
constructor(element, options = {}) {
let defaults = {
placeholder: 'Select item(s)',
max: null,
search: true,
selectAll: true,
listAll: true,
closeListOnItemSelect: false,
name: '',
width: '',
height: '',
dropdownWidth: '',
dropdownHeight: '',
data: [],
onChange: function() {},
onSelect: function() {},
onUnselect: function() {}
};
this.options = Object.assign(defaults, options);
this.selectElement = typeof element === 'string' ? document.querySelector(element) : element;
for(const prop in this.selectElement.dataset) {
if (this.options[prop] !== undefined) {
this.options[prop] = this.selectElement.dataset[prop];
}
}
this.name = this.selectElement.getAttribute('name') ? this.selectElement.getAttribute('name') : 'multi-select-' + Math.floor(Math.random() * 1000000);
if (!this.options.data.length) {
let options = this.selectElement.querySelectorAll('option');
for (let i = 0; i < options.length; i++) {
this.options.data.push({
value: options[i].value,
text: options[i].innerHTML,
selected: options[i].selected,
html: options[i].getAttribute('data-html')
});
}
}
this.element = this._template();
this.selectElement.replaceWith(this.element);
this._updateSelected();
this._eventHandlers();
}
_template() {
let optionsHTML = '';
for (let i = 0; i < this.data.length; i++) {
optionsHTML += `
<div class="multi-select-option${this.selectedValues.includes(this.data[i].value) ? ' multi-select-selected' : ''}" data-value="${this.data[i].value}">
<span class="multi-select-option-radio"></span>
<span class="multi-select-option-text">${this.data[i].html ? this.data[i].html : this.data[i].text}</span>
</div>
`;
}
let selectAllHTML = '';
if (this.options.selectAll === true || this.options.selectAll === 'true') {
selectAllHTML = `<div class="multi-select-all">
<span class="multi-select-option-radio"></span>
<span class="multi-select-option-text">Select all</span>
</div>`;
}
let template = `
<div class="multi-select ${this.name}"${this.selectElement.id ? ' id="' + this.selectElement.id + '"' : ''} style="${this.width ? 'width:' + this.width + ';' : ''}${this.height ? 'height:' + this.height + ';' : ''}">
${this.selectedValues.map(value => `<input type="hidden" name="${this.name}[]" value="${value}">`).join('')}
<div class="multi-select-header" style="${this.width ? 'width:' + this.width + ';' : ''}${this.height ? 'height:' + this.height + ';' : ''}">
<span class="multi-select-header-max">${this.options.max ? this.selectedValues.length + '/' + this.options.max : ''}</span>
<span class="multi-select-header-placeholder">${this.placeholder}</span>
</div>
<div class="multi-select-options" style="${this.options.dropdownWidth ? 'width:' + this.options.dropdownWidth + ';' : ''}${this.options.dropdownHeight ? 'height:' + this.options.dropdownHeight + ';' : ''}">
${this.options.search === true || this.options.search === 'true' ? '<input type="text" class="multi-select-search" placeholder="Search...">' : ''}
${selectAllHTML}
${optionsHTML}
</div>
</div>
`;
let element = document.createElement('div');
element.innerHTML = template;
return element;
}
_eventHandlers() {
let headerElement = this.element.querySelector('.multi-select-header');
this.element.querySelectorAll('.multi-select-option').forEach(option => {
option.onclick = () => {
let selected = true;
if (!option.classList.contains('multi-select-selected')) {
if (this.options.max && this.selectedValues.length >= this.options.max) {
return;
}
option.classList.add('multi-select-selected');
if (this.options.listAll === true || this.options.listAll === 'true') {
if (this.element.querySelector('.multi-select-header-option')) {
let opt = Array.from(this.element.querySelectorAll('.multi-select-header-option')).pop();
opt.insertAdjacentHTML('afterend', `<span class="multi-select-header-option" data-value="${option.dataset.value}">${option.querySelector('.multi-select-option-text').innerHTML}</span>`);
} else {
headerElement.insertAdjacentHTML('afterbegin', `<span class="multi-select-header-option" data-value="${option.dataset.value}">${option.querySelector('.multi-select-option-text').innerHTML}</span>`);
}
}
this.element.querySelector('.multi-select').insertAdjacentHTML('afterbegin', `<input type="hidden" name="${this.name}[]" value="${option.dataset.value}">`);
this.data.filter(data => data.value == option.dataset.value)[0].selected = true;
} else {
option.classList.remove('multi-select-selected');
this.element.querySelectorAll('.multi-select-header-option').forEach(headerOption => headerOption.dataset.value == option.dataset.value ? headerOption.remove() : '');
this.element.querySelector(`input[value="${option.dataset.value}"]`).remove();
this.data.filter(data => data.value == option.dataset.value)[0].selected = false;
selected = false;
}
if (this.options.listAll === false || this.options.listAll === 'false') {
if (this.element.querySelector('.multi-select-header-option')) {
this.element.querySelector('.multi-select-header-option').remove();
}
headerElement.insertAdjacentHTML('afterbegin', `<span class="multi-select-header-option">${this.selectedValues.length} selected</span>`);
}
if (!this.element.querySelector('.multi-select-header-option')) {
headerElement.insertAdjacentHTML('afterbegin', `<span class="multi-select-header-placeholder">${this.placeholder}</span>`);
} else if (this.element.querySelector('.multi-select-header-placeholder')) {
this.element.querySelector('.multi-select-header-placeholder').remove();
}
if (this.options.max) {
this.element.querySelector('.multi-select-header-max').innerHTML = this.selectedValues.length + '/' + this.options.max;
}
if (this.options.search === true || this.options.search === 'true') {
this.element.querySelector('.multi-select-search').value = '';
}
this.element.querySelectorAll('.multi-select-option').forEach(option => option.style.display = 'flex');
if (this.options.closeListOnItemSelect === true || this.options.closeListOnItemSelect === 'true') {
headerElement.classList.remove('multi-select-header-active');
}
this.options.onChange(option.dataset.value, option.querySelector('.multi-select-option-text').innerHTML, option);
if (selected) {
this.options.onSelect(option.dataset.value, option.querySelector('.multi-select-option-text').innerHTML, option);
} else {
this.options.onUnselect(option.dataset.value, option.querySelector('.multi-select-option-text').innerHTML, option);
}
};
});
headerElement.onclick = () => headerElement.classList.toggle('multi-select-header-active');
if (this.options.search === true || this.options.search === 'true') {
let search = this.element.querySelector('.multi-select-search');
search.oninput = () => {
this.element.querySelectorAll('.multi-select-option').forEach(option => {
option.style.display = option.querySelector('.multi-select-option-text').innerHTML.toLowerCase().indexOf(search.value.toLowerCase()) > -1 ? 'flex' : 'none';
});
};
}
if (this.options.selectAll === true || this.options.selectAll === 'true') {
let selectAllButton = this.element.querySelector('.multi-select-all');
selectAllButton.onclick = () => {
let allSelected = selectAllButton.classList.contains('multi-select-selected');
this.element.querySelectorAll('.multi-select-option').forEach(option => {
let dataItem = this.data.find(data => data.value == option.dataset.value);
if (dataItem && ((allSelected && dataItem.selected) || (!allSelected && !dataItem.selected))) {
option.click();
}
});
selectAllButton.classList.toggle('multi-select-selected');
};
}
if (this.selectElement.id && document.querySelector('label[for="' + this.selectElement.id + '"]')) {
document.querySelector('label[for="' + this.selectElement.id + '"]').onclick = () => {
headerElement.classList.toggle('multi-select-header-active');
};
}
document.addEventListener('click', event => {
if (!event.target.closest('.' + this.name) && !event.target.closest('label[for="' + this.selectElement.id + '"]')) {
headerElement.classList.remove('multi-select-header-active');
}
});
}
_updateSelected() {
if (this.options.listAll === true || this.options.listAll === 'true') {
this.element.querySelectorAll('.multi-select-option').forEach(option => {
if (option.classList.contains('multi-select-selected')) {
this.element.querySelector('.multi-select-header').insertAdjacentHTML('afterbegin', `<span class="multi-select-header-option" data-value="${option.dataset.value}">${option.querySelector('.multi-select-option-text').innerHTML}</span>`);
}
});
} else {
if (this.selectedValues.length > 0) {
this.element.querySelector('.multi-select-header').insertAdjacentHTML('afterbegin', `<span class="multi-select-header-option">${this.selectedValues.length} selected</span>`);
}
}
if (this.element.querySelector('.multi-select-header-option')) {
this.element.querySelector('.multi-select-header-placeholder').remove();
}
}
get selectedValues() {
return this.data.filter(data => data.selected).map(data => data.value);
}
get selectedItems() {
return this.data.filter(data => data.selected);
}
set data(value) {
this.options.data = value;
}
get data() {
return this.options.data;
}
set selectElement(value) {
this.options.selectElement = value;
}
get selectElement() {
return this.options.selectElement;
}
set element(value) {
this.options.element = value;
}
get element() {
return this.options.element;
}
set placeholder(value) {
this.options.placeholder = value;
}
get placeholder() {
return this.options.placeholder;
}
set name(value) {
this.options.name = value;
}
get name() {
return this.options.name;
}
set width(value) {
this.options.width = value;
}
get width() {
return this.options.width;
}
set height(value) {
this.options.height = value;
}
get height() {
return this.options.height;
}
}
document.querySelectorAll('[data-multi-select]').forEach(select => new MultiSelect(select));
The code will automatically create a new instance of the class if the data-multi-select attribute is specified on one or more select elements, meaning all we essentially have to do is include the JS file in our HTML document with:
<script src="MultiSelect.js"></script>
Preferably at the bottom of the document before the body closing tag.
However, if we want to customize it further with custom HTML, etc, we can dynamically create a new instance and include additional options. It's pretty straightforward, so you shouldn't encounter any issues getting started!
3. Examples
In this section, we'll cover practical examples that will help guide you into integrating the multi-select dropdown element in your own projects.
3.1. Simple Dropdown
Let's start with a simple dropdown element with minimal configuration.
Add the following code to your HTML document:
<label for="fruits">Fruits</label>
<select id="fruits" name="fruits" data-placeholder="Select fruits" multiple data-multi-select>
<option value="Apple">Apple</option>
<option value="Banana">Banana</option>
<option value="Blackberry">Blackberry</option>
<option value="Blueberry">Blueberry</option>
<option value="Cherry">Cherry</option>
<option value="Cranberry">Cranberry</option>
<option value="Grapes">Grapes</option>
<option value="Kiwi">Kiwi</option>
<option value="Mango">Mango</option>
<option value="Orange">Orange</option>
<option value="Peach">Peach</option>
<option value="Pear">Pear</option>
<option value="Pineapple">Pineapple</option>
<option value="Raspberry">Raspberry</option>
<option value="Strawberry">Strawberry</option>
<option value="Watermelon">Watermelon</option>
</select>
So here, we are basically creating our multi-select dropdown element using the native select element. The data-multi-select attribute will determine the type of element. We actually don't need to declare any JS code because all the data is specified within the select element, and to apply our customizable options, we can declare data attributes (data-placeholder, data-max, data-search, etc.).
The snippet above will resemble the following:
If we want to preselect some of the items, we can simply add the selected attribute, like so:
<option value="Cranberry" selected>Cranberry</option>
As we can see, the class utilizes native methods, so it's much easier to convert existing elements without the hassle of rewriting the entire code.
3.2. Customizing Options with Data Attributes
To customize existing select elements, we can specify data attributes based on our requirements. Let's go ahead and start applying new options to our multi-select dropdown box.
Limiting the Number of Selectable Items
To limit the number of items we can select in the dropdown, we can implement the data-max attribute to our element, like so:
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
In the above example, the user can only select two items from the dropdown list. If we want to increase/decrease the maximum items, we can increment/decrement the data-max value.
Search Function
The search function will enable us to enter a query inside an input box and subsequently filter the items. By default, the search function is enabled, but we can disable it by specifying the data-search attribute, like so:
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" data-search="false" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
Ideally, you would want to disable it if your dropdown list contains only a few items.
Select All Function
The select all function will enable us to check and uncheck all items in the dropdown list with a single click of a button. Like previously, the select all function is enabled by default, but we can disable it with:
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" data-search="false" data-select-all="false" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
And just like that, the select all function is disabled.
List All Function
The list all function basically populates all the items in the selected items area. We can disable it with the following code:
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" data-search="false" data-select-all="false" data-list-all="false" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
If disabled, it will appear in "X selected" format as opposed to populating each individual item.
Useful if you expect the user to select a large number of items from the dropdown list. It will prevent the UI from being cumbersome.
Adjusting the Height and Width
We can set the default height and width in our stylesheet, but if we want to change the size for a particular dropdown element, we can implement the data-width and data-height attributes, like so:
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" data-search="false" data-select-all="false" data-list-all="false" data-width="300px" data-height="50px" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
Both options aren't mandatory, so you can remove one or the other. The size can be calculated in different formats (pixels, percentages, ems, etc.).
And to customize the size of the dropdown list, we can implement the data-dropdown-width and data-dropdown-height attributes.
With all the options applied above, the multi-select dropdown will resemble the following:
Next up, we'll delve into more advanced methods.
3.3. Dynamic Creation with Custom HTML
Finally, we've reached the fun part of the article! In this section, we'll explore various methods to dynamically generate our multi-select dropdown boxes using JavaScript.
Let's go ahead and create our dynamic select container with the following code:
<label for="dynamic">Dynamic Select</label>
<select id="dynamic" name="dynamic"></select>
The type of the element is irrelevant, meaning we could use a DIV container as opposed to the select element. It's entirely up to you!
Right then! This is where it gets interesting... Let's create a new instance of the MultiSelect class and add some data with custom HTML content. To do that, add the following code to your HTML document:
<script>
// Initialize the Multi Select dropdown
new MultiSelect('#dynamic', {
data: [
{
value: 'opt1',
text: 'Option 1'
},
{
value: 'opt2',
html: '<strong>Option 2 with HTML!</strong>'
},
{
value: 'opt3',
text: 'Option 3',
selected: true
},
{
value: 'opt4',
text: 'Option 4'
},
{
value: 'opt5',
text: 'Option 5'
}
],
placeholder: 'Select an option',
search: true,
selectAll: true,
listAll: false,
max: 2
});
</script>
The first parameter selects the element in our HTML document — there are various techniques to select elements. In our case, the hashtag character is prepended to the value, so it will select the element with the ID attribute followed by the value.
The data array consists of objects that will populate items in our dropdown. If we want to customize individual items, we can add the html property (see the second item in the array), which will override the text property.
TipYou can declare multiple instances of the MultiSelect class with different parameters, meaning you can have more than one multi-select dropdown.
With all the data attributes we implemented earlier, we can apply them in a similar format as shown in the example.
Change Event Listener
When the dropdown list has been changed, the change method will be triggered. We can add the event listener with the following code:
<script>
// Initialize the Multi Select dropdown
new MultiSelect('#dynamic', {
data: ...,
onChange: function(value, text, element) {
console.log('Change:', value, text, element);
}
});
</script>
That will output the arguments to the browser console (item value, etc.).
Select Event Listener
In some cases, we want to execute an event listener that will be triggered when an item is selected. To do that, we can add the following:
<script>
// Initialize the Multi Select dropdown
new MultiSelect('#dynamic', {
data: ...,
onSelect: function(value, text, element) {
console.log('Selected:', value, text, element);
}
});
</script>
And now, when an item is selected, the item args will be logged to the browser console.
Unselect Event Listener
But what about unselect? We've got you covered! Simply add the following:
<script>
// Initialize the Multi Select dropdown
new MultiSelect('#dynamic', {
data: ...,
onUnselect: function(value, text, element) {
console.log('Unselected:', value, text, element);
}
});
</script>
Pretty neat, right? With the event listeners listed above, there are no limits to what you can do with the multi-select class.
3.4. Full Source Code
Below is the full source code with all the examples outlined in this article.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1">
<title>Multi Select JS</title>
<!-- Include the Multi Select stylesheet -->
<link href="MultiSelect.css" rel="stylesheet" type="text/css">
<style>
* {
box-sizing: border-box;
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
}
body {
margin: 0;
padding: 15px;
background-color: #f3f4f7;
}
form {
display: flex;
flex-direction: column;
margin: 100px auto;
padding: 40px 40px 60px;
max-width: 500px;
width: 100%;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
form h1 {
margin: 10px 0 5px;
font-size: 24px;
font-weight: 500;
color: #474b50;
}
form label {
margin: 25px 0 10px;
font-weight: 500;
color: #474b50;
}
</style>
</head>
<body>
<form>
<h1>Multi Select Dropdown</h1>
<label for="fruits">Fruits</label>
<select id="fruits" name="fruits" data-placeholder="Select fruits" multiple data-multi-select>
<option value="Apple">Apple</option>
<option value="Banana">Banana</option>
<option value="Blackberry">Blackberry</option>
<option value="Blueberry">Blueberry</option>
<option value="Cherry">Cherry</option>
<option value="Cranberry">Cranberry</option>
<option value="Grapes">Grapes</option>
<option value="Kiwi">Kiwi</option>
<option value="Mango">Mango</option>
<option value="Orange">Orange</option>
<option value="Peach">Peach</option>
<option value="Pear">Pear</option>
<option value="Pineapple">Pineapple</option>
<option value="Raspberry">Raspberry</option>
<option value="Strawberry">Strawberry</option>
<option value="Watermelon">Watermelon</option>
</select>
<label for="cars">Car Manufacturers</label>
<select id="cars" name="cars" data-placeholder="Select car manufacturers" data-max="2" data-search="false" data-select-all="false" data-list-all="false" data-width="300px" data-height="50px" multiple data-multi-select>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Chevrolet">Chevrolet</option>
</select>
<label for="dynamic">Dynamic Select</label>
<select id="dynamic" name="dynamic"></select>
</form>
<!-- Include the Multi Select JS class -->
<script src="MultiSelect.js"></script>
<script>
// Initialize the Multi Select dropdown
new MultiSelect('#dynamic', {
data: [
{
value: 'opt1',
text: 'Option 1'
},
{
value: 'opt2',
html: '<strong>Option 2 with HTML!</strong>'
},
{
value: 'opt3',
text: 'Option 3',
selected: true
},
{
value: 'opt4',
text: 'Option 4'
},
{
value: 'opt5',
text: 'Option 5'
}
],
placeholder: 'Select an option',
search: true,
selectAll: true,
listAll: false,
max: 2,
onChange: function(value, text, element) {
console.log('Change:', value, text, element);
},
onSelect: function(value, text, element) {
console.log('Selected:', value, text, element);
},
onUnselect: function(value, text, element) {
console.log('Unselected:', value, text, element);
}
});
</script>
</body>
</html>
Don't forget to add the MultiSelect.css stylesheet and MultiSelect.js JavaScript class files to your project folder.
4. Reference
Below, you'll find the reference tables for the MultiSelect.js class.
Option | Type | Default | Description |
placeholder | String | Select item(s) | The default placeholder text for the multi-select element. |
name | String | empty | The name attribute for the select element. |
max | Number | null | The maximum number of items that can be selected. If null, there is no limit. |
search | Boolean | true | Determines whether the search function is enabled or disabled. |
selectAll | Boolean | true | Determines whether the select all function is enabled or disabled. |
listAll | Boolean | true | Determines whether the list all function is enabled or disabled. If disabled, the selected value will appear as "X selected". |
width | String | empty | The width of the multi-select element, specified as a CSS value (e.g., '100px', '50%'). |
height | String | empty | The height of the multi-select element, specified as a CSS value. |
dropdownWidth | String | empty | The width of the multi-select dropdown element, specified as a CSS value (e.g., '100px', '50%'). |
dropdownHeight | String | empty | The height of the multi-select dropdown element, specified as a CSS value. |
data | Array | empty | An array of objects representing each item in the select element. See the reference table below. |
onChange | Function | function() {} | A callback function that's executed when the selected item changes. It receives the selected value and other relevant data as arguments. |
onSelect | Function | function() {} | A callback function that's executed when an item is selected. |
onUnselect | Function | function() {} | A callback function that's executed when an item is unselected. |
The reference table for the data array.
Property | Type | Description |
value | String | The value attribute of the item in the multi-select element. |
text | String | The display text for the item. |
selected | Boolean | Determines whether the option is selected by default. |
html | String | Custom HTML content for the item. If provided, it overrides the text property. |
To apply the properties to inline select elements, we can prepend data- to the property name and declare it in our element along with the value.
Conclusion
Modernizing the native select elements is imperative for sites seeking long-term growth and user-friendly design. With modern JS, the possibilities are endless. That being said, this guide aims to cover all aspects related to multi-select dropdowns with practical examples and a robust JS class.
Looking for another UI element with customizable options? Let us know your suggestions in the comments section below. We'd love to hear from you!
You can download the full source code from our GitHub repository: https://github.com/codeshackio/multi-select-dropdown-js
Thanks for reading!
Released under the MIT license.