27

When there is a long set of elements in a datalist, they will all get displayed with a scroll bar next to them. Is there an easy way to only display the top 5, and just cut the others off?

For example: http://jsfiddle.net/yxafa/

<input type="text" name="search" id="search" placeholder="type 'r'" list="searchresults" autocomplete="off">
<datalist id="searchresults">
    <option>Ray0</option>
    <option>Ray1</option>
    <option>Ray2</option>
    <option>Ray3</option>
    <option>Ray01</option>
    <option>Ray11</option>
    <option>Ray21</option>
    <option>Ray31</option>
    <option>Ray02</option>
    <option>Ray12</option>
    <option>Ray22</option>
    <option>Ray32</option>
    <option>Ray012</option>
    <option>Ray112</option>
    <option>Ray212</option>
    <option>Ray312</option>
    <option>Ray03</option>
    <option>Ray13</option>
    <option>Ray23</option>
    <option>Ray33</option>
    <option>Ray013</option>
    <option>Ray113</option>
    <option>Ray213</option>
    <option>Ray313</option>
    <option>Ray023</option>
    <option>Ray123</option>
    <option>Ray223</option>
    <option>Ray323</option>
    <option>Ray0123</option>
    <option>Ray1123</option>
    <option>Ray2123</option>
    <option>Ray3123</option>
</datalist>
unor
  • 92,415
  • 26
  • 211
  • 360
Gus
  • 1,905
  • 6
  • 23
  • 37
  • 1
    Come on! Interesting question, +1! Why there are no answers!? – Jacek Kowalewski May 28 '14 at 08:35
  • Well, i don't think this i possible atm. You can only reduce the set of displayed items by adding other requirement like `maxlength="4"` or `pattern="Ray[0123]\d"` – Möhre May 30 '14 at 09:57
  • Also note that, at the time of writing (May 2014) the `template` tag is only supported in Chrome, Opera Desktop, and Mozilla FF. [See here](http://caniuse.com/#search=template). Same for [`datalist`](http://caniuse.com/#search=datalist), + partial support for IE 10+ – webketje May 30 '14 at 12:20

3 Answers3

13

With some modern javascript and html you could do something like this.

Here's the document:

<template id="resultstemplate">
    <option>Ray0</option>
    <option>Ray1</option>
    <option>Ray2</option>
    <option>Ray3</option>
    <option>Ray01</option>
    <option>Ray11</option>
    <option>Ray21</option>
    <option>Ray31</option>
    <option>Ray02</option>
    <option>Ray12</option>
    <option>Ray22</option>
    <option>Ray32</option>
    <option>Ray012</option>
    <option>Ray112</option>
    <option>Ray212</option>
    <option>Ray312</option>
    <option>Ray03</option>
    <option>Ray13</option>
    <option>Ray23</option>
    <option>Ray33</option>
    <option>Ray013</option>
    <option>Ray113</option>
    <option>Ray213</option>
    <option>Ray313</option>
    <option>Ray023</option>
    <option>Ray123</option>
    <option>Ray223</option>
    <option>Ray323</option>
    <option>Ray0123</option>
    <option>Ray1123</option>
    <option>Ray2123</option>
    <option>Ray3123</option>
</template>
<input type="text" name="search" id="search"  placeholder="type 'r'" list="searchresults" autocomplete="off" />
<datalist id="searchresults"></datalist>

And here's the js:

var search = document.querySelector('#search');
var results = document.querySelector('#searchresults');
var templateContent = document.querySelector('#resultstemplate').content;
search.addEventListener('keyup', function handler(event) {
    while (results.children.length) results.removeChild(results.firstChild);
    var inputVal = new RegExp(search.value.trim(), 'i');
    var clonedOptions = templateContent.cloneNode(true);
    var set = Array.prototype.reduce.call(clonedOptions.children, function searchFilter(frag, el) {
        if (inputVal.test(el.textContent) && frag.children.length < 5) frag.appendChild(el);
        return frag;
    }, document.createDocumentFragment());
    results.appendChild(set);
});

And here's a live example: http://jsfiddle.net/gildean/yxafa/6/

Olli K
  • 1,720
  • 1
  • 16
  • 17
  • Just wonderin', why use `document.querySelector` in this case instead of `getElementById` when the latter is much faster & more efficient? http://jsperf.com/getelementbyid-vs-queryselector – webketje May 30 '14 at 12:14
  • 1
    It's just a nicer api to remember. And in this example we're only doing all of the selecting once, so it makes no difference. – Olli K May 30 '14 at 12:28
1

No javascript example:

  <input list="site" name="f" minlength="2" style="height:5.1em">
  <datalist id="site" style="height:5.1em;overflow:hidden">

Took me a minute :)

This uses CSS style and HTML attributes. PS: The minimum length should protect against empty submissions. However, you'll need to select the object and then hit backspace to see :|

Aeron R
  • 75
  • 8
  • 2
    a minute of experimenting, and a minute for explanation. I'm sure you can do better explanation of the settings. – Mike Castro Demaria Aug 07 '20 at 16:45
  • Oh yes, sorry. The extra entries will be hidden, because they will exceed the height of "5.1em". I've edited the example to include "overflow:hidden". – Aeron R Aug 12 '20 at 00:52
1

This is not an answer to the original question (where the developer wants to limit the items shown in the datalist)

However I arrived at this question because I was concerned about a different limitation (where the developers does not want to limit the items shown in the datalist; but the browser has a limit (Chrome has a limit of 512; only shows up to 512 options at a time)

This JSFiddle demonstrates the problem; see screenshot below.

Of course, as the user begins typing in the input (which filters the options shown in the datalist), there may be fewer than 512 results, so this browser-limitation would not be noticeable. But if your user expects to see every single option in your datalist and the filtered results count >512, be careful of the Chrome limitation.

searchresults = document.getElementById('searchresults');

// Even though you add 1000 options to the datalist 
// chrome will only show up to 512 of those options at one time
for (let i = 0; i < 1000; i++) {
  let option = document.createElement('option');
  option.innerText = 'Val ' + (i+1);
  searchresults.appendChild(option);
}

on the left, code shows adding 1000 options to a datalist, on the right the UI shows only up to 512 of those options will be listed at once

If you need to show > 512 options...

Consider a <select> instead (in many browser implementations, a user can focus on a select, start typing, and in doing so "filter" the selected option. But this is limited to searching the start of a word, and may not handle special characters.)

Consider a UI library with "autocomplete"/"combobox" control (example in KendoUI's "Combobox") or creating your own (example in AngularJS)

Nate Anderson
  • 18,334
  • 18
  • 100
  • 135