152

Currently the HTML5 <datalist> element is supported in most major browsers (except Safari) and seems like an interesting way to add suggestions to an input.

However, there seem to be some discrepancies between the implementation of the value attribute and the inner text on the <option>. For example:

<input list="answers" name="answer">
<datalist id="answers">
  <option value="42">The answer</option>
</datalist>

This is handled differently by different browsers:

Chrome and Opera:
Datalist in Chrome/Opera

FireFox and IE 11:
Datalist in FireFox

After selecting one, the input is filled with the value and not the inner text. I only want the user to see the text ("The answer") in the dropdown and in the input, but pass the value 42 on submit, like a select would.

How can I make all browsers have the dropdown list show the labels (inner text) of the <option>s, but send the value attribute when the form is submitted?

Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
  • 2
    I think Firefox and IE11 are wrong here; according to the specs [One](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) and [Two](http://www.w3.org/TR/2011/WD-html5-author-20110809/the-option-element.html#the-option-element), it seems that `value=""` should take precedence over a string within the tags, whenever there is a `value=""` declared. So the suggestion would be to make "the answer" your value attribute. – TylerH Apr 26 '15 at 21:11
  • 2
    @TylerH No - Firefox and IE11 are correct here: The label attribute provides a label for element. **The label of an option element is the value of the label content attribute, if there is one, or, if there is not, the value of the element's text IDL attribute.** http://www.w3.org/TR/html5/forms.html#attr-option-label – easwee May 04 '15 at 07:18
  • 1
    @easwee That just says the label should be what's in label if there is a label, and that the value should be what's in the value if there is a value. It doesn't specify which one takes precedence. – TylerH May 04 '15 at 13:59

6 Answers6

167

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

Adam M.
  • 1,071
  • 1
  • 7
  • 23
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
  • 3
    how would you deal with options with same innertext but different data-values? e.g. http://jsfiddle.net/7k3sovht/78/ – bigbearzhu Mar 03 '16 at 22:05
  • 2
    As far as I can tell, there's no way to differentiate between the two options. Because there is no user event to listen to it's impossible to know which of the two they actually selected; all we know is what value ended up in the input field. – Stephan Muller Mar 04 '16 at 14:40
  • @StephanMuller great answer for someone who is learning more HTML5 like me, thanks! How would you clear out the textbox for the demo after submit? – Chris22 Jan 23 '17 at 17:15
  • Pure jquery document.querySelector('input[list]').addEventListener('input', function(e) { var value = $(this).val(); var list = $(this).attr('list'); var id = $(this).attr('id'); $('#'+list+' option').each(function(){ if($(this).val() == value){ $('#'+id+'-hidden').val($(this).attr('data-value')); } }); }); – Piotr Kazuś Apr 04 '17 at 07:43
  • @StephanMuller thanks for sharing, very useful, I'm running as you coded, however I get the data-value just when using backspace in the input, not when submitting or even selecting a differetn item, what can be wrong? – digitai Feb 08 '18 at 19:46
  • @StephanMuller your answer is so clear, I was just using the , instead of . Now it works as expected, thanks, – digitai Feb 08 '18 at 19:57
  • Thank you this is a good solution but it doesn't work if the option has some white spaces in begining or end, or two white spaces consecutives, I don't know why but the input is trimming automatically the datalist options : `` – Stephane L Feb 09 '18 at 12:09
  • The text is not trimmed when it is in the value attribute : `` – Stephane L Feb 09 '18 at 14:10
  • @bigbearzhu, for that case where the values could be identical, use both value="" and data-value="" for – Lucian Minea Apr 16 '18 at 11:47
  • It doesn't work when on one page are two datalists. What I do wrong? I change name & id in forms. What else do I have to do – harbii Jul 16 '21 at 16:22
71

The solution I use is the following:

<input list="answers" id="answer">
<datalist id="answers">
  <option data-value="42" value="The answer">
</datalist>

Then access the value to be sent to the server using JavaScript like this:

var shownVal = document.getElementById("answer").value;
var value2send = document.querySelector("#answers option[value='"+shownVal+"']").dataset.value;


Hope it helps.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Hezbullah Shah
  • 888
  • 6
  • 16
  • I am getting undefined any reason? – Dejell Nov 23 '16 at 10:28
  • 1
    Trouble shoot with console.log at each step. Make sure you are using same id value which you are calling. And check semicollons too. – Hezbullah Shah Nov 23 '16 at 14:41
  • @ApurvG this is the variable storing the value shown in the field. – Hezbullah Shah Apr 19 '18 at 10:29
  • 1
    this solution is such a great idea! - i was able to, rather simply, implement this solution in minutes. first i updated my `input` element with attribute `data-value="1"`. Then i wrote the following block in the places where the value was being grabbed and used: `if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }` – WEBjuju Mar 02 '20 at 21:20
  • 5
    But what if you have two equals captions with some different data-values – Richard Aguirre Aug 20 '20 at 15:29
  • 1
    Thanks Hezbullah Shah you really saved so much hours – ABODE Sep 16 '20 at 22:48
12

I realize this may be a bit late, but I stumbled upon this and was wondering how to handle situations with multiple identical values, but different keys (as per bigbearzhu's comment).

So I modified Stephan Muller's answer slightly:

A datalist with non-unique values:

<input list="answers" name="answer" id="answerInput">
<datalist id="answers">
  <option value="42">The answer</option>
  <option value="43">The answer</option>
  <option value="44">Another Answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

When the user selects an option, the browser replaces input.value with the value of the datalist option instead of the innerText.

The following code then checks for an option with that value, pushes that into the hidden field and replaces the input.value with the innerText.

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

    if (options.length > 0) {
      hiddenInput.value = input.value;
      input.value = options[0].innerText;
      }

});

As a consequence the user sees whatever the option's innerText says, but the unique id from option.value is available upon form submit. Demo jsFiddle

cobbystreet
  • 121
  • 1
  • 2
1

When clicking on the button for search you can find it without a loop.
Just add to the option an attribute with the value you need (like id) and search for it specific.

$('#search_wrapper button').on('click', function(){
console.log($('option[value="'+ 
$('#autocomplete_input').val() +'"]').data('value'));
})
Mangaldeep Pannu
  • 3,738
  • 2
  • 26
  • 45
0

to get text() instead of val() try:

$("#datalistid option[value='" + $('#inputid').val() + "']").text();
Saghachi
  • 851
  • 11
  • 19
-17

Using PHP i've found a quite simple way to do this. Guys, Just Use something like this

<input list="customers" name="customer_id" required class="form-control" placeholder="Customer Name">
            <datalist id="customers">
                <?php 
    $querySnamex = "SELECT * FROM `customer` WHERE fname!='' AND lname!='' order by customer_id ASC";
    $resultSnamex = mysqli_query($con,$querySnamex) or die(mysql_error());

                while ($row_this = mysqli_fetch_array($resultSnamex)) {
                    echo '<option data-value="'.$row_this['customer_id'].'">'.$row_this['fname'].' '.$row_this['lname'].'</option>
                    <input type="hidden" name="customer_id_real" value="'.$row_this['customer_id'].'" id="answerInput-hidden">';
                }

                 ?>
            </datalist>

The Code Above lets the form carry the id of the option also selected.

23r0
  • 1
  • 2
  • That seems like a mess and smells like SQL injection. Don't do that. – Fusseldieb Jul 01 '19 at 12:42
  • 1
    @23r0, some feedback as to why this may have been voted down; this question is about frontend code specifically. Including backend code (like PHP) may be unnecessary and confusing. Regarding the HTML, I expect you'll only ever get the last value for `customer_id_real` submitted, not the selected value. – John Oct 05 '19 at 06:32
  • @Fusseldieb as it doesn't take any user input it is perfectly safe. IMHO It's a pretty harsh statement marking it as so. – Rune Kaagaard Feb 15 '21 at 13:59
  • @RuneKaagaard I don't see any sqlinjection possibilities IN HIS/HER ANSWER too. But it should be noted for others: just because an input is hidden, readonly or deactivated, it still get's send to the server. Even if a normal user cannot input something, it is possible with the browsers devtools => sqlinjections are possible. Backend should always distrust frontend. – aProgger Jan 16 '22 at 10:20