├── auto-complete.css ├── auto-complete.js ├── auto-complete.min.js ├── bower.json ├── demo.html ├── img ├── at.png ├── au.png ├── bg.png ├── br.png ├── ca.png ├── ch.png ├── cn.png ├── cz.png ├── de.png ├── dk.png ├── es.png ├── fi.png ├── fr.png ├── hu.png ├── in.png ├── it.png ├── ja.png ├── nl.png ├── no.png ├── pt.png ├── ro.png ├── ru.png ├── tr.png └── us.png └── readme.md /auto-complete.css: -------------------------------------------------------------------------------- 1 | .autocomplete-suggestions { 2 | text-align: left; cursor: default; border: 1px solid #ccc; border-top: 0; background: #fff; box-shadow: -1px 1px 3px rgba(0,0,0,.1); 3 | 4 | /* core styles should not be changed */ 5 | position: absolute; display: none; z-index: 9999; max-height: 254px; overflow: hidden; overflow-y: auto; box-sizing: border-box; 6 | } 7 | .autocomplete-suggestion { position: relative; padding: 0 .6em; line-height: 23px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 1.02em; color: #333; } 8 | .autocomplete-suggestion b { font-weight: normal; color: #1f8dd6; } 9 | .autocomplete-suggestion.selected { background: #f0f0f0; } 10 | -------------------------------------------------------------------------------- /auto-complete.js: -------------------------------------------------------------------------------- 1 | /* 2 | JavaScript autoComplete v1.0.4 3 | Copyright (c) 2014 Simon Steinberger / Pixabay 4 | GitHub: https://github.com/Pixabay/JavaScript-autoComplete 5 | License: http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | var autoComplete = (function(){ 9 | // "use strict"; 10 | function autoComplete(options){ 11 | if (!document.querySelector) return; 12 | 13 | // helpers 14 | function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); } 15 | 16 | function addEvent(el, type, handler){ 17 | if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); 18 | } 19 | function removeEvent(el, type, handler){ 20 | // if (el.removeEventListener) not working in IE11 21 | if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); 22 | } 23 | function live(elClass, event, cb, context){ 24 | addEvent(context || document, event, function(e){ 25 | var found, el = e.target || e.srcElement; 26 | while (el && !(found = hasClass(el, elClass))) el = el.parentElement; 27 | if (found) cb.call(el, e); 28 | }); 29 | } 30 | 31 | var o = { 32 | selector: 0, 33 | source: 0, 34 | minChars: 3, 35 | delay: 150, 36 | offsetLeft: 0, 37 | offsetTop: 1, 38 | cache: 1, 39 | menuClass: '', 40 | renderItem: function (item, search){ 41 | // escape special characters 42 | search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); 43 | var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi"); 44 | return '
' + item.replace(re, "$1") + '
'; 45 | }, 46 | onSelect: function(e, term, item){} 47 | }; 48 | for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; } 49 | 50 | // init 51 | var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector); 52 | for (var i=0; i 0) 78 | that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; 79 | else if (selTop < 0) 80 | that.sc.scrollTop = selTop + scrTop; 81 | } 82 | } 83 | } 84 | addEvent(window, 'resize', that.updateSC); 85 | document.body.appendChild(that.sc); 86 | 87 | live('autocomplete-suggestion', 'mouseleave', function(e){ 88 | var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); 89 | if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20); 90 | }, that.sc); 91 | 92 | live('autocomplete-suggestion', 'mouseover', function(e){ 93 | var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); 94 | if (sel) sel.className = sel.className.replace('selected', ''); 95 | this.className += ' selected'; 96 | }, that.sc); 97 | 98 | live('autocomplete-suggestion', 'mousedown', function(e){ 99 | if (hasClass(this, 'autocomplete-suggestion')) { // else outside click 100 | var v = this.getAttribute('data-val'); 101 | that.value = v; 102 | o.onSelect(e, v, this); 103 | that.sc.style.display = 'none'; 104 | } 105 | }, that.sc); 106 | 107 | that.blurHandler = function(){ 108 | try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; } 109 | if (!over_sb) { 110 | that.last_val = that.value; 111 | that.sc.style.display = 'none'; 112 | setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input 113 | } else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20); 114 | }; 115 | addEvent(that, 'blur', that.blurHandler); 116 | 117 | var suggest = function(data){ 118 | var val = that.value; 119 | that.cache[val] = data; 120 | if (data.length && val.length >= o.minChars) { 121 | var s = ''; 122 | for (var i=0;i 40) && key != 13 && key != 27) { 164 | var val = that.value; 165 | if (val.length >= o.minChars) { 166 | if (val != that.last_val) { 167 | that.last_val = val; 168 | clearTimeout(that.timer); 169 | if (o.cache) { 170 | if (val in that.cache) { suggest(that.cache[val]); return; } 171 | // no requests if previous suggestions were empty 172 | for (var i=1; i'+e.replace(o,"$1")+""},onSelect:function(){}};for(var c in e)e.hasOwnProperty(c)&&(l[c]=e[c]);for(var a="object"==typeof l.selector?[l.selector]:document.querySelectorAll(l.selector),u=0;u0?i.sc.scrollTop=n+i.sc.suggestionHeight+s-i.sc.maxHeight:0>n&&(i.sc.scrollTop=n+s)}else i.sc.scrollTop=0},o(window,"resize",i.updateSC),document.body.appendChild(i.sc),n("autocomplete-suggestion","mouseleave",function(){var e=i.sc.querySelector(".autocomplete-suggestion.selected");e&&setTimeout(function(){e.className=e.className.replace("selected","")},20)},i.sc),n("autocomplete-suggestion","mouseover",function(){var e=i.sc.querySelector(".autocomplete-suggestion.selected");e&&(e.className=e.className.replace("selected","")),this.className+=" selected"},i.sc),n("autocomplete-suggestion","mousedown",function(e){if(t(this,"autocomplete-suggestion")){var o=this.getAttribute("data-val");i.value=o,l.onSelect(e,o,this),i.sc.style.display="none"}},i.sc),i.blurHandler=function(){try{var e=document.querySelector(".autocomplete-suggestions:hover")}catch(t){var e=0}e?i!==document.activeElement&&setTimeout(function(){i.focus()},20):(i.last_val=i.value,i.sc.style.display="none",setTimeout(function(){i.sc.style.display="none"},350))},o(i,"blur",i.blurHandler);var r=function(e){var t=i.value;if(i.cache[t]=e,e.length&&t.length>=l.minChars){for(var o="",s=0;st||t>40)&&13!=t&&27!=t){var o=i.value;if(o.length>=l.minChars){if(o!=i.last_val){if(i.last_val=o,clearTimeout(i.timer),l.cache){if(o in i.cache)return void r(i.cache[o]);for(var s=1;s 2 | 3 | 4 | Vanilla JavaScript autoComplete 5 | 6 | 7 | 8 | 9 | 10 | 51 | 52 | 53 | 54 |
55 |

autoComplete

56 |

An extremely lightweight and powerful vanilla JavaScript completion suggester.

57 | Download 58 |   59 | View on GitHub 60 |
61 |
62 | 63 |
64 |
65 |

Overview and Features

66 |

67 | Released under the MIT License. 68 | Source on Github (changelog). 69 | Tested in Firefox, Safari, Chrome, Opera, Internet Explorer 8+. 70 |

71 |
    72 |
  • Lightweight: 5.4 kB of JavaScript - less than 2.4 kB gzipped
  • 73 |
  • Written in plain JavaScript, no dependencies and lightning fast
  • 74 |
  • Fully flexible data source
  • 75 |
  • Smart caching, delay and minimum character settings
  • 76 |
  • Callbacks
  • 77 |
78 |

79 | This plugin was developed by Pixabay.com - an international repository for free Public Domain images. 80 | We have implemented this piece of software in production on plainJS and we share it - in the spirit of Pixabay - freely with others. 81 |

82 | 83 |

Usage

84 |

85 | Include the JavaScript file auto-complete.min.js before the closing </body> tag 86 | and the stylesheet auto-complete.css in the <head> section of your page. 87 | autoComplete accepts settings from an object of key/value pairs, and can be assigned to any text input field. 88 |

89 |
// initialize
 90 | var my_autoComplete = new autoComplete({key1: value1, key2: value2});
 91 | 
 92 | // destroy
 93 | my_autoComplete.destroy();
94 | 95 |

Settings

96 | 97 | 98 | 99 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 118 | 119 | 120 | 121 | 129 | 130 | 131 | 132 | 133 | 139 | 140 | 141 | 142 | 143 |
PropertyDefaultDescription
selectorstring or DOM elementRequired selector for text input field or DOM element.
source(term, response)null 100 | Required callback function to connect any data source to autoComplete. The callback gets two arguments: 101 |
    102 |
  • term, which refers to the value currently in the text input.
  • 103 |
  • A response callback, which expects a single argument: 104 | the data to suggest to the user. This data must be an array of filtered suggestions based on the provided term: 105 |
    ['suggestion 1', 'suggestion 2', 'suggestion 3', ...] 106 |
  • 107 |
108 |
minChars3Minimum number of characters (>=1) a user must type before a search is performed.
delay150The delay in milliseconds between when a keystroke occurs and when a search is performed. A zero-delay is more responsive, but can produce a lot of load.
offsetLeft0Optional left offset of the suggestions container.
offsetTop1Optional top offset of the suggestions container.
cachetrueDetermines if performed searches should be cached.
menuClass''Custom class/es that get/s added to the dropdown menu container. 117 |
Example: { menuClass: 'class1 class2' }
renderItemfunction 122 |

A function that gives you control over how suggestions are displayed. Default:

123 |
renderItem: function (item, search){
124 |     search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
125 |     var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
126 |     return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item.replace(re, "<b>$1</b>") + '</div>';
127 | }
128 |
 
Callbacks
onSelect(event, term, item) 134 | A callback function that fires when a suggestion is selected by mouse click, enter, or tab. 135 | event is the event that triggered the callback, 136 | term is the selected value. 137 | and item is the item rendered by the renderItem function. 138 |
 
Public Methods
destroyRemoves the autoComplete instance and its bindings.
144 | 145 |

Demos

146 | 147 |

Searching in local data

148 |

149 | This plugin was designed mainly with AJAX requests in mind, but it may be used with local data, as well. 150 | Connecting the autocompletion suggester to an array of strings can be done in the source function like so: 151 |

152 |
new autoComplete({
153 |     selector: 'input[name="q"]',
154 |     minChars: 2,
155 |     source: function(term, suggest){
156 |         term = term.toLowerCase();
157 |         var choices = ['ActionScript', 'AppleScript', 'Asp', ...];
158 |         var matches = [];
159 |         for (i=0; i<choices.length; i++)
160 |             if (~choices[i].toLowerCase().indexOf(term)) matches.push(choices[i]);
161 |         suggest(matches);
162 |     }
163 | });
164 |

165 | The source function iterates through an array of (local) choices and we return a new array containing all (lowercased) matches. 166 | Simple as that. 167 |

168 | 169 |

AJAX requests

170 |

171 | AJAX requests may come with very different requirements: JSON, JSONP, GET, POST, additionaly params, authentications, etc. 172 | In order to keep the source code small while retaining full flexibility, we decided to only use a simple callback function as the source for suggestions. 173 | Make your AJAX call inside this function and return matching suggestions with the response callback. For brevity, this example uses jQuery for AJAX: 174 |

175 |
new autoComplete({
176 |     selector: 'input[name="q"]',
177 |     source: function(term, response){
178 |         $.getJSON('/some/ajax/url/', { q: term }, function(data){ response(data); });
179 |     }
180 | });
181 |

182 | The AJAX call in this example needs to return an array of strings. 183 | The callback response must always be called, even if no suggestions are returned or if an error occured. 184 | This ensures the correct state of the autoComplete instance. 185 |

186 | 187 |

Optimizing AJAX requests

188 |

189 | All search results are cached by default and unnecessary requests are prevented in order to keep server load as low as possible. 190 | To further reduce server impact, it's possible to abort unfinished AJAX requests before starting new ones. 191 | Again using jQuery's AJAX method for brevity: 192 |

193 |
var xhr;
194 | new autoComplete({
195 |     selector: 'input[name="q"]',
196 |     source: function(term, response){
197 |         try { xhr.abort(); } catch(e){}
198 |         xhr = $.getJSON('/some/ajax/url/', { q: term }, function(data){ response(data); });
199 |     }
200 | });
201 |

202 | By typing along, the user may trigger one AJAX request after the other. 203 | With this little trick, we make sure that only the most current one actually gets executed - if not done so already. 204 |

205 | 206 |

Advanced suggestions handling and custom layout

207 |

208 | By making use of the renderItem() function, it's possible to turn the autocompleter into an item suggester: 209 |

210 |
211 | 212 |
213 |

214 | While typing country names or language codes, a list of matching suggestions is displayed. E.g. typing "de" will show "Germany" as a suggestion, because "de" is the language code for German. 215 | Source code for this example: 216 |

217 |
new autoComplete({
218 |     selector: 'input[name=&quot;q&quot;]',
219 |     minChars: 1,
220 |     source: function(term, suggest){
221 |         term = term.toLowerCase();
222 |         var choices = [['Australia', 'au'], ['Austria', 'at'], ['Brasil', 'br'], ...];
223 |         var suggestions = [];
224 |         for (i=0;i<choices.length;i++)
225 |             if (~(choices[i][0]+' '+choices[i][1]).toLowerCase().indexOf(term)) suggestions.push(choices[i]);
226 |         suggest(suggestions);
227 |     },
228 |     renderItem: function (item, search){
229 |         search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
230 |         var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
231 |         return '<div class="autocomplete-suggestion" data-langname="'+item[0]+'" data-lang="'+item[1]+'" data-val="'+search+'"><img src="img/'+item[1]+'.png"> '+item[0].replace(re, "<b>$1</b>")+'</div>';
232 |     },
233 |     onSelect: function(e, term, item){
234 |         alert('Item "'+item.getAttribute('data-langname')+' ('+item.getAttribute('data-lang')+')" selected by '+(e.type == 'keydown' ? 'pressing enter' : 'mouse click')+'.');
235 |     }
236 | });
237 |

238 | In this case, autocompleting the text field is not desired, so we turn it off by setting data-val="'+search+'" in the renderItem() function. 239 | However, when choosing an item, the onSelect() callback returns all required information. 240 |

241 | 242 |
243 | 244 |
245 | 246 |
247 |
248 |
249 |
250 |
251 |
252 | 253 |

Please report any bugs and issues at the GitHub repositiory.

254 |

This software is released as Open Source under the MIT License by Simon Steinberger / Pixabay.com.

255 |
256 | 257 |
258 |
259 | About Us 260 | Blog 261 | More Goodies 262 | © Pixabay.com / Simon Steinberger / Hans Braxmeier 263 |
264 |
265 | 266 |
267 | 268 | 314 | 315 | 316 | 317 | -------------------------------------------------------------------------------- /img/at.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/at.png -------------------------------------------------------------------------------- /img/au.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/au.png -------------------------------------------------------------------------------- /img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/bg.png -------------------------------------------------------------------------------- /img/br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/br.png -------------------------------------------------------------------------------- /img/ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/ca.png -------------------------------------------------------------------------------- /img/ch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/ch.png -------------------------------------------------------------------------------- /img/cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/cn.png -------------------------------------------------------------------------------- /img/cz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/cz.png -------------------------------------------------------------------------------- /img/de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/de.png -------------------------------------------------------------------------------- /img/dk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/dk.png -------------------------------------------------------------------------------- /img/es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/es.png -------------------------------------------------------------------------------- /img/fi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/fi.png -------------------------------------------------------------------------------- /img/fr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/fr.png -------------------------------------------------------------------------------- /img/hu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/hu.png -------------------------------------------------------------------------------- /img/in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/in.png -------------------------------------------------------------------------------- /img/it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/it.png -------------------------------------------------------------------------------- /img/ja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/ja.png -------------------------------------------------------------------------------- /img/nl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/nl.png -------------------------------------------------------------------------------- /img/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/no.png -------------------------------------------------------------------------------- /img/pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/pt.png -------------------------------------------------------------------------------- /img/ro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/ro.png -------------------------------------------------------------------------------- /img/ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/ru.png -------------------------------------------------------------------------------- /img/tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/tr.png -------------------------------------------------------------------------------- /img/us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pixabay/JavaScript-autoComplete/eda3201210a86f7fcfb7f496f4b2ca419ff423e8/img/us.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | JavaScript-autoComplete 2 | =================== 3 | 4 | An extremely lightweight and powerful vanilla JavaScript completion suggester. 5 | 6 | Tested in Firefox, Safari, Chrome, Opera, Internet Explorer 8+. No dependencies, written in plain JavaScript. 7 | Released under the MIT License: http://www.opensource.org/licenses/mit-license.php 8 | 9 | This plugin was developed by [Pixabay.com](https://pixabay.com/) - an international repository for sharing free public domain images. 10 | We have implemented this piece of software in production on [plainJS](https://plainjs.com/) and we share it - in the spirit of Pixabay - freely with others. 11 | 12 | ## Demo and Documentation 13 | 14 | https://goodies.pixabay.com/javascript/auto-complete/demo.html 15 | 16 | ## Features 17 | 18 | * Lightweight: 5.4 kB of JavaScript - less than 2.4 kB gzipped 19 | * Fully flexible data source 20 | * Smart caching, delay and minimum character settings 21 | * Callbacks 22 | 23 | ## Changelog 24 | 25 | ### Version 1.0.4 - 2016/02/10 26 | 27 | * Included pull #6 and added offsetLeft/offsetTop as optional parameter for suggestions container. 28 | 29 | 30 | ### Version 1.0.3 - 2015/11/02 31 | 32 | * Fixed #2: Unspecified error on IE 10. 33 | 34 | ### Version 1.0.2 - 2015/08/15 35 | 36 | * Fixed: Hide suggestions on fast input. 37 | * Fixed: Select item with tab. 38 | * Fixed: Incorrect selection by mouse when suggestions are scrolled down. 39 | 40 | ### Version 1.0.1 - 2015/06/08 41 | 42 | * Simplified code and minor bug fixes. 43 | 44 | ### Version 1.0.0 - 2015/06/07 45 | 46 | * Prevent unnecessary search on pressing enter. 47 | 48 | ### Version 1.0.0 beta - 2015/05/12 49 | 50 | * First release 51 | --------------------------------------------------------------------------------