HTML multiple selections with datalist

 
 
  • Gérald Barré
 

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:

Source code of the demo: demo.zip
HTML
<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:

HTML
<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:

TypeScript
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!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub