DEV Community

Cover image for Customise Datalist
Siddhant Jaiswal
Siddhant Jaiswal

Posted on • Edited on

Customise Datalist

Intro

Most web developers often do not know about all the HTML tags/elements there are, and it's not their fault as well there are close to 100 tags and remembering the functionality for all is quite difficult as a result our web apps end mostly made of divs, paragraphs, lists, spans and headers, but I would suggest we start using section tag, article tag, address tags as well in our apps and for forms we should start using fieldset, legend and datalist as well. These will help your applications be more accessible to people with special needs and in today's world we should make our apps accessible to everyone.

What is Datalist?

In simple words datalist when combined with input elements provides a searchable dropdown options to select from. It's more like select and options elements on steroids. 🤣🤣🤣
A basic example of datalist is below:

As you can see, we get an input field where you can type and the options gets filtered based on your inputs and it's a great out of box element, but the only caveat is that the dropdown styles depend on the browser you are using so it will be different on Firefox edge opera chrome etc. which is not good as most designers and developers prefers consistency throughout their apps/websites.
Now the good news is we can customise the datalist using CSS but we will have to disable/ignore the OOB datalist functionality and rewrite the functionality using JavaScript and the result is below:

Now how do you do this? well, it's pretty simple, let me explain:

DIY

  • First of we create and input tag and add list attribute to it. This list attribute will take in the id of our datalist element
<input autocomplete="off" list="browsers" id="input"
name="browsers" placeholder="Select your fav browser">
Enter fullscreen mode Exit fullscreen mode
  • Next up we will create our datalist element with ID as browsers and inside the datalist element will have some option elements as well and voila your basic datalist is complete.
<datalist id="browsers">
  <option value="Internet Explorer">Internet Explorer</option>
  <option value="Chrome">Chrome</option>
  <option value="Safari">Safari</option>
  <option value="Microsoft Edge">Microsoft Edge</option>
  <option value="Firefox">Firefox</option>
</datalist>
Enter fullscreen mode Exit fullscreen mode
  • Now to customise the datalist first thing we need to do is disable the OOB datalist and to do that we simply need to pass empty string to our input list attribute.
<input autocomplete="off" list="" id="input" 
name="browsers" placeholder="Select your fav browser">
Enter fullscreen mode Exit fullscreen mode
  • Now we will add some basic CSS to our datalist and options elements
datalist {
  position: absolute;
  background-color: white;
  border: 1px solid blue;
  border-radius: 0 0 5px 5px;
  border-top: none;
  font-family: sans-serif;
  width: 350px;
  padding: 5px;

}

option {
  background-color: white;
  padding: 4px;
  color: blue;
  margin-bottom: 1px;
   font-size: 18px;
  cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode
Please not CSS for input element can be found in codepen above.
  • Now we want the our datalist to be displayed when the focus on our input element and for this we will some Javascript.
input.onfocus = function () {
  browsers.style.display = 'block';
  input.style.borderRadius = "5px 5px 0 0";  
};
for (let option of browsers.options) {
  option.onclick = function () {
    input.value = option.value;
    browsers.style.display = 'none';
    input.style.borderRadius = "5px";
  }
};
Enter fullscreen mode Exit fullscreen mode

We will also add hover styling so that the option is highlighted when we hover over any option

option:hover, .active{
  background-color: lightblue;
}
Enter fullscreen mode Exit fullscreen mode
We will use active class later.

Now this will make your datalist work and users will be able to select any option via mouse but won't work with keyboard input.

  • Next up we will try to filter to the options based on input values. To do that we will create an oninput trigger and get the values then will match the values with our options and display only the options that match with input values.
input.oninput = function() {
  var text = input.value.toUpperCase();
  for (let option of browsers.options) {
    if(option.value.toUpperCase().indexOf(text) > -1){
      option.style.display = "block";
  }else{
    option.style.display = "none";
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

Here we simply take the input value convert them to uppercase and then see if that input is present at any index for each option values. if yes then display it else hide it.

  • Next will add the functionality for tracking the options via keyboard up and down arrow keys and select any option using enter. For this we will need to track the currectFocus for our option element so we will define a variable as currentFocus = -1, then check for keyboard input keycode to be up or down arrow keys and toggle the active class defined earlier.
var currentFocus = -1;
input.onkeydown = function(e) {
  if(e.keyCode == 40){
    currentFocus++
   addActive(browsers.options);
  }
  else if(e.keyCode == 38){
    currentFocus--
   addActive(browsers.options);
  }
  else if(e.keyCode == 13){
    e.preventDefault();
        if (currentFocus > -1) {
          if (browsers.options) 
browsers.options[currentFocus].click();
        }
  }
}

function addActive(x) {
    if (!x) return false;
    removeActive(x);
    if (currentFocus >= x.length) currentFocus = 0;
    if (currentFocus < 0) 
       currentFocus = (x.length - 1);
    x[currentFocus].classList.add("active");
  }
  function removeActive(x) {
    for (var i = 0; i < x.length; i++) {
      x[i].classList.remove("active");
    }
  }
Enter fullscreen mode Exit fullscreen mode

and we have recreated the default datalist.

Conclusion

I hope this helps you all who have been trying to use datalist but were unable to use because of lack of support of customization. I hope that in future browsers provide us more freedom to customise the datalist without rewriting the JavaScript to recreate the functionality and with just CSS we can achieve our desired result. 🤞🤞🤞

If you find any bugs or if you can improve the functionality, please feel free to do so and add the link for your codepen in the comments below so that me and others can also try to improve our skills. 😃

Thanks for reading. Please share it with your collegues and developer friends and family.

happyCodding.

Top comments (8)

Collapse
 
roesler profile image
Roesler

So if I understand this correctly... you turned of every 'key-feature' of a datalist and rewrote it just to style it and be able to use with your own styles? In hope to be able to style it more nativly in future? I like that optimism! :)

Collapse
 
siddev profile image
Siddhant Jaiswal

Yes like data list doesn’t work properly on iOS devices

Collapse
 
mkastner profile image
mtkastner

This is an awesome styling, considering the few styling options for datalists. It's a really nice approach.

Collapse
 
siddev profile image
Siddhant Jaiswal

Thanks
I hope in a very near future more styling options will come

Collapse
 
tohodo profile image
Tommy

A good start, however I noticed two issues:

  1. As soon as you select an entry from the datalist menu, the datalist stops working.
  2. The datalist menu doesn't scroll when yo navigate using the keyboard.
Collapse
 
artydev profile image
artydev

Thank you :-)

Collapse
 
jordanfinners profile image
Jordan Finneran

How accessible is this solution? 😊

Collapse
 
siddev profile image
Siddhant Jaiswal • Edited

Well I have not added any aria tags in the artice but you can aria-role="combobox" to the input and role="listbox" to datalist

Update: I have added aria tags to make this datalist accessible.