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">
- 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>
- 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">
- 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;
}
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";
}
};
We will also add hover styling so that the option is highlighted when we hover over any option
option:hover, .active{
background-color: lightblue;
}
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";
}
};
}
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");
}
}
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.
Top comments (8)
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! :)
Yes like data list doesn’t work properly on iOS devices
This is an awesome styling, considering the few styling options for datalists. It's a really nice approach.
Thanks
I hope in a very near future more styling options will come
A good start, however I noticed two issues:
Thank you :-)
How accessible is this solution? 😊
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.