How to Style The Drop-Down Suggestions When Using HTML5 <Datalist>

Is there a way to apply a CSS style on HTML5 datalist options?

Like select elements, the datalist element has very little flexibility in styling. You cannot style any of the suggested terms if that's what your question was asking.

Browsers define their own styles for these elements.

Styling is not Working on option of datalist

you can customise the datalist using CSS but you'll have to disable/ignore the OOB datalist functionality and rewrite the functionality using JavaScript and the result is below:

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";
}
};

input.oninput = function() {
currentFocus = -1;
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";
}
};
}
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) {
/*and simulate a click on the "active" item:*/
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");
}
}
input {
font-size: 18px;
padding: 5px;
height: 35px;
width: 350px;
border: 1px solid #000;
outline: none;
border-radius: 5px;
color: #000;
/* border-bottom: none; */
}

datalist {
position: absolute;
background-color: white;
border: 1px solid #000;
border-radius: 0 0 5px 5px;
border-top: none;
width: 350px;
padding: 5px;
}

option {
background-color: white;
padding: 4px;
color: #000;
margin-bottom: 1px;
font-size: 18px;
cursor: pointer;
background: #eeeeee
}

option:hover,
.active {
background-color: red;
}
<input autocomplete="off" role="combobox" list="" id="input" name="browsers">
<!-- Its important that you keep list attribute empty to hide the default dropdown icon and the browser's default datalist -->

<datalist id="browsers" role="listbox">
<option value="Chrome">Chrome</option>
<option value="Safari">Safari</option>
<option value="Microsoft Edge">Microsoft Edge</option>
</datalist>

Select intelligently from a drop down list

Suppose you have a datalist like below :

<datalist id="locations">
<option value="India taj mahal">
<option value="India Qutub Minar">
<option value="China gate">
</datalist>

Now you can select all option values and put them in an array like below :

var options = document.getElementById('locations').options;
var values = [];
for(var i=0; i<options.length; i++)
{
values.push(options[i].value);
}

Now let's suppose your search term is India Minar, so you can build a search logic something like below :

var searchTerm = "India Minar";

var searchSplit = searchTerm.split(" ");

var availableSearches = [];

for(var i=0; i<values.length; i++) {
for(var j=0; j<searchSplit.length; j++) {
if(values[i].indexOf(searchSplit[j]) >= 0 &&
availableSearches.indexOf(values[i]) < 0){
availableSearches.push(values[i]);
}
}
}

console.log(availableSearches);
//["India taj mahal", "India Qutub Minar"]

This logic will search text with both India and Minar in the collection. If this is not exactly you are looking for, you can easily tweak logic.

Show datalist labels but submit the actual value

Note that datalist is not the same as a select. It allows users to enter a custom value that is not in the list, and it would be impossible to fetch an alternate value for such input without defining it first.

Possible ways to handle user input are to submit the entered value as is, submit a blank value, or prevent submitting. This answer handles only the first two options.

If you want to disallow user input entirely, maybe select would be a better choice.


To show only the text value of the option in the dropdown, we use the inner text for it and leave out the value attribute. The actual value that we want to send along is stored in a custom data-value attribute:

To submit this data-value we have to use an <input type="hidden">. In this case we leave out the name="answer" on the regular input and move it to the hidden copy.

<input list="suggestionList" id="answerInput">
<datalist id="suggestionList">
<option data-value="42">The answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

This way, when the text in the original input changes we can use javascript to check if the text also present in the datalist and fetch its data-value. That value is inserted into the hidden input and submitted.

document.querySelector('input[list]').addEventListener('input', function(e) {
var input = e.target,
list = input.getAttribute('list'),
options = document.querySelectorAll('#' + list + ' option'),
hiddenInput = document.getElementById(input.getAttribute('id') + '-hidden'),
inputValue = input.value;

hiddenInput.value = inputValue;

for(var i = 0; i < options.length; i++) {
var option = options[i];

if(option.innerText === inputValue) {
hiddenInput.value = option.getAttribute('data-value');
break;
}
}
});

The id answer and answer-hidden on the regular and hidden input are needed for the script to know which input belongs to which hidden version. This way it's possible to have multiple inputs on the same page with one or more datalists providing suggestions.

Any user input is submitted as is. To submit an empty value when the user input is not present in the datalist, change hiddenInput.value = inputValue to hiddenInput.value = ""


Working jsFiddle examples: plain javascript and jQuery



Related Topics



Leave a reply



Submit