[HTML][JS] Input + datalist with validation instead of selects

Last time I implemented something like mix of select and input fields. User can type name, but should value in field should be from defined group. It should not only provide selection dropdown menu, but also suggestions during typing. There are a lot of ready solutions, but I decided to use native HTML5 tag – datelist. It’s very nice, so I decided to describe its and some issues with browsers.

Datalist tag – basic usage

I think describing this tag is not important, because you can find many information over internet, for example on w3schools. In brief: this tag allows us to create possible options for input autocomplete. Basic usage is very simple, we must just add list atribute to input field and define available options. Of course, datalist tag isn’t visible on page in default (but you can change this using CSS):

<input list="browsers">

<datalist id="browsers">
    <option value="Internet Explorer">
    <option value="Firefox">
    <option value="Chrome">
    <option value="Opera">
    <option value="Safari">
</datalist>

And… it’s all. It will work fine – you can see dropdown menu in input and also autocomplete options during typing. But there is one issue – it isn’t supported by all browser. There is no problem with Chrome, Opera, Firefox, Edge and their clones (ex. based on Blink engine), but Internet Explorer 9 and older will not support datalist. Is it real issue? I think now, IE9 is very old browser (released on 2011), there is also IE10 and IE11. If someone still uses Internet Explorer, should use newest version because of security and other compatibility concerns.

Compatibility issues with Safari

Bigger trouble is fact, that also Safari doesn’t support datalist tag. Not only old and outdated version from Windows, but also the newest from MacOS and iOS. I don’t know why Apple not implemented this tag, but if our clients use browser, we must make additional fixes. Fortunately, there are some polyfills on Github, that can support datalist on Safair. One of them is purejs-datalist-polyfill. Usage is very simple: just add script and CSS code. We don’t need to use jQuery or any external libraries. Datalist will be transformed to list and suggested, not only in Safair, but also on older Internet Explorer versions and old Android browser.

Datalist with validation

Ok, but that about validation? Datalist provide us only autocomplete, it doesn’t force user to select one of available options – it’s like a input with search, but we can still type anything. I must change this, because in that case, user can type, but value must be from specific group. Other page elements use jQuery, jQueryUI and validate plugin, so I decided to use these libraries to add „compatibility” layer and also validation. First step: if we doesn’t use select with for example numeric values and text labels, there must be additional hidden field to store value and allows us to validate field:

<input type="text" list="listPersons" id="inputPersonName" class="validateOnDatalist" placeholder="Please type" name="inputPersonName" value="">
<input type="hidden" id="inputPersonId" class="hiddenVal" value="0">

Second step is to create datalist with all available values and data-personid attribute with our numeric value (like on select options):

<datalist id="listPersons">
    <option value="Alfred" data-personid="1">
    <option value="Fred" data-personid="4">
    <option value="John" data-personid="6">
    <option value="Mike" data-personid="7">
</datalist>

Then we can add action for changing input field and modify hidden field. I use several events, because user can not only typing, but also use autocomplete or just paste value:

$("#inputPersonName").on("change keydown input paste", function() {
    var selectedOption = $("#listPersons option[value='" + $(this).val() + "']");
    var selectedPerson = parseInt(selectedOption.attr('data-empid-clean'));

    if (selectedPerson) {
        $('#inputPersonId').val(selectedPerson);
    } else {
        $('#inputPersonId').val('');
    }
});

And there is validation code for jQuery validation plugin:

jQuery.validator.addMethod("onDatalist", function (value, element) {
    var hiddenVal = parseInt($(element).siblings('input.hiddenVal').val());
    return !!(hiddenVal);
});

jQuery.validator.addClassRules(
    "validateOnDatalist",
    { onDatalist: true }
);

This code will add validation for all inputs with validateOnDatalist class, so you can easily add new inputs and new datalist. Last step is to add compatibility layer (it’s optional), because polyfill mentioned before will not work with that validation and hidden field. We can you autocomplete from jQueryUI and just transform available options to autocomplete list:

$(document).ready(function () {
    initDatalists();
});
function initDatalists() {
    var datalistSupported = !!(document.createElement('datalist') && window.HTMLDataListElement);
    if (!datalistSupported) {
        $('input[list]').each(function () {
            var node = $(this);
            var availableTags = $('#' + $(this).attr("list")).find('option').map(function () {
                return this.value;
            }).get();
            $(this).autocomplete({
                source: availableTags,
                select: function(event, ui) {
                    setTimeout(function() {
                        $(node).change();
                    }, 10);
                }
            });
        });
    }
}

It’s all. With that code, we can easily create predefined lists for inputs and validate data on user side (important: we should ALWAYS validate any input data also on backend!). It’s only example, but I think it shows that tag potential – we can dynamically change list for input ex. when one list depends from other. There is also much, much much faster that very big selects i.e. selects with many options. I saw big page scrolling issues when we use several selects with 20+ options, input + datalist are much lighter.