Skip to main content Accessibility Feedback

How to work with multiselect elements in vanilla JS

On Friday, we looked at how to get and set values in select elements. Then, yesterday, we learned how to loop through all of the options in a select element and look at its properties.

Today, we’re going to learn how to work with multiselect elements. Let’s dig in.

An example

Let’s say you have a select element like this.

<label for="dnd">What's the best class in D&D?</label>
<select id="dnd">
	<option value="bard">Bard</option>
	<option value="fighter">Fighter</option>
	<option value="druid">Druid</option>
	<option value="paladin">Paladin</option>
	<option value="rogue">Rogue</option>
	<option value="wizard">Wizard</option>
</select>

But instead of picking just one option, you want users to be able to select multiple options. You can do that by adding the multiple property to your select element.

Note: For things like this, checkboxes are typically a better choice. Users often find multi-select elements confusing and unintuitive. They create usability issues.

<label for="dnd">What are the best classes in D&D?</label>
<select id="dnd" multiple>
	<option value="bard">Bard</option>
	<option value="fighter">Fighter</option>
	<option value="druid">Druid</option>
	<option value="paladin">Paladin</option>
	<option value="rogue">Rogue</option>
	<option value="wizard">Wizard</option>
</select>

Now, a user can hold the shift button while clicking (touchscreen devices surface a different UI for these) to select multiple items.

Here’s a demo.

Getting the value of a multi-select element

The problem with a multi-select element (beyond their general usability issues) is that there’s no one-line property to get all of the selected values.

The value property only returns the first selected value rather than all values.

// Get the select element
var dnd = document.querySelector('#dnd');

// Get it's value
// This returns the first selected value, not all selected values
dnd.value;

Here’s an updated demo.

To get all selected values, we need to use the technique we learned yesterday to loop through each of the options and check if it’s selected.

First, let’s get our HTMLOptionsCollection and turn it into an array with the Array.from() method.

// Convert all of the options to an array
var selected = Array.from(dnd.options);

Then, using the Array.filter() method and the selected property, we can create a new array containing only the option elements that have been selected.

// Convert all of the options to an array
// Then, get an array of only the options that are selected
var selected = Array.from(dnd.options).filter(function (option) {
	return option.selected;
});

Finally, we’ll use the Array.map() method to create an array with the value of each selected item. Because Array.filter() returns an array, we can chain Array.map() to it.

// Convert all of the options to an array
// Then, get an array of only the options that are selected
// Then, get an array of the selected option values
var selected = Array.from(dnd.options).filter(function (option) {
	return option.selected;
}).map(function (option) {
	return option.value;
});

Here’s a demo of this approach in action.

Setting or updating the values in a multi-select element

Let’s say you had an array of values, and you wanted to update your multi-select with those values.

// Bard and Wizard are the best classes in D&D, obvs
var selected = ['bard', 'wizard'];

Like in yesterday’s article, we’re going to loop through each option element with Array.forEach().

We’ll check to see if that items value is in the selected array. If it is, we’ll use the option.selected property to true. Otherwise, we’ll set it to false to remove any existing selections.

// Get an array of option elements and loop through them
Array.from(dnd.options).forEach(function (option) {

	// If the option's value is in the selected array, select it
	// Otherwise, deselect it
	if (selected.includes(option.value)) {
		option.selected = true;
	} else {
		option.selected = false;
	}

});

Because the Array.includes() method returns a boolean, you could shorten this by setting the option.selected value to whatever the method returns.

// Get an array of option elements and loop through them
Array.from(dnd.options).forEach(function (option) {

	// If the option's value is in the selected array, select it
	// Otherwise, deselect it
	option.selected = selected.includes(option.value);

});

Here’s a demo of updating values based on an array of data.

Browser compatibility

The Array.from() method works in all modern browsers, but not IE. You can polyfill it, or use the Array.prototype.slice.call() hack.

// Converts an array-like object into an array
Array.prototype.slice.call(dnd.options);

The Array.includes() method in a newer method that works in all modern browsers, but not IE. You can polyfill it, or use the Array.indexOf() method instead.

// If the option's value is in the selected array, select it
// Otherwise, deselect it
if (selected.indexOf(option.value) > -1) {
	option.selected = true;
} else {
	option.selected = false;
}