HTML multiple selections with datalist
The multiple
attribute (specification) on an <input>
element is used to indicate that multiple values can be selected. However, browsers don't support this attribute when using a <datalist>
element. Only one element will be suggested.
Let's improve input to support datalists and multiple values! Here's the final result:
<input type="text" list="Suggestions" multiple />
<datalist id="Suggestions">
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
</datalist>
The idea is to dynamically edit the option
element of the datalist
while you are typing to remove selected values and prefix all others with the already selected values. For instance, if the input value is option 2,
, the HTML will be:
<input type="text" list="Suggestions" multiple value="option 2," />
<datalist id="Suggestions">
<option>option 2, option 1</option>
<option>option 2, option 3</option>
</datalist>
Here's the TypeScript code to dynamically update the datalist
's children:
document.addEventListener("DOMContentLoaded", function () {
const separator = ',';
for (const input of document.getElementsByTagName("input")) {
if (!input.multiple) {
continue;
}
if (input.list instanceof HTMLDataListElement) {
const optionsValues = Array.from(input.list.options).map(opt => opt.value);
let valueCount = input.value.split(separator).length;
input.addEventListener("input", () => {
const currentValueCount = input.value.split(separator).length;
// Do not update list if the user doesn't add/remove a separator
// Current value: "a, b, c"; New value: "a, b, cd" => Do not change the list
// Current value: "a, b, c"; New value: "a, b, c," => Update the list
// Current value: "a, b, c"; New value: "a, b" => Update the list
if (valueCount !== currentValueCount) {
const lsIndex = input.value.lastIndexOf(separator);
const str = lsIndex !== -1 ? input.value.substr(0, lsIndex) + separator : "";
filldatalist(input, optionsValues, str);
valueCount = currentValueCount;
}
});
}
}
function filldatalist(input: HTMLInputElement, optionValues: string[], optionPrefix: string) {
const list = input.list;
if (list && optionValues.length > 0) {
list.innerHTML = "";
const usedOptions = optionPrefix.split(separator).map(value => value.trim());
for (const optionsValue of optionValues) {
if (usedOptions.indexOf(optionsValue) < 0) { // Skip used values
const option = document.createElement("option");
option.value = optionPrefix + optionsValue;
list.append(option);
}
}
}
}
});
When you add this script in your page it should detect input with the multiple
attribute and update its behavior with the datalist
.
Do you have a question or a suggestion about this post? Contact me!