Menu

jQuery Typeahead Search: Demo Version 2.7.1 6 hours ago

Examples of how the jQuery Typeahead Search can be used to improve a search bar. The following examples shows variations and possible results that can be achieved using this JavaScript plugin.

Basic demos

Country v1
  • Simple initialization with local data (country list)
  • Reorder the search results desc (descending)
  • onInit callback to perform an action


    $.typeahead({
        input: '.js-typeahead-country_v1',
        order: "desc",
        source: {
            data: [
                "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and Barbuda",
                "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh",
                "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
                "Bosnia and Herzegovina", "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina Faso", "Burma",
                "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Republic", "Chad",
                "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic", "Congo, Republic of the",
                "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti",
                "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador",
                "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", "Gabon",
                "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Greenland", "Grenada", "Guatemala", "Guinea",
                "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India",
                "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan",
                "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kuwait", "Kyrgyzstan", "Laos",
                "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
                "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
                "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Mongolia", "Morocco", "Monaco",
                "Mozambique", "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger",
                "Nigeria", "Norway", "Oman", "Pakistan", "Panama", "Papua New Guinea", "Paraguay", "Peru",
                "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Samoa", "San Marino",
                "Sao Tome", "Saudi Arabia", "Senegal", "Serbia and Montenegro", "Seychelles", "Sierra Leone",
                "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "Spain",
                "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan",
                "Tajikistan", "Tanzania", "Thailand", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
                "Turkmenistan", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States",
                "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe"
            ]
        },
        callback: {
            onInit: function (node) {
                console.log('Typeahead Initiated on ' + node.selector);
            }
        }
    });
        

        

    
Country v2
  • The typeahead search contains multiple lists country & capital
  • A custom template for the search result. {{display}} represents the default index, {{group}} represents option.source.group the item is located in, "capital" or "country".
  • The data is fetched locally via an ajax request object /jquerytypeahead/country_v2.json.

    • A POST request will be sent with data myKey: myValue.
    • country.ajax.path = data.country is used to reach the proper index inside the JSON response.
  • onResult modifies the text inside #result-container to display the total results.
  • The ul.typeahead__list has max-height: 300px; and is scrollable, onNavigateAfter is set to scroll the result container if arrow UP or DOWN are pressed to the .active item.
  • onMouseEnter callback adds custom HTML to display the country flag (Only a few are available for this demo, try: United States, France, Germany, Italy, Mexico, Brazil, Canada)


    $.typeahead({
        input: '.js-typeahead-country_v2',
        minLength: 1,
        maxItem: 20,
        order: "asc",
        href: "https://en.wikipedia.org/?title={{display}}",
        template: "{{display}} <small style='color:#999;'>{{group}}</small>",
        source: {
            country: {
                ajax: {
                    url: "/jquerytypeahead/country_v2.json",
                    path: "data.country"
                }
            },
            capital: {
                ajax: {
                    type: "POST",
                    url: "/jquerytypeahead/country_v2.json",
                    path: "data.capital",
                    data: {myKey: "myValue"}
                }
            }
        },
        callback: {
            onNavigateAfter: function (node, lis, a, item, query, event) {
                if (~[38,40].indexOf(event.keyCode)) {
                    var resultList = node.closest("form").find("ul.typeahead__list"),
                        activeLi = lis.filter("li.active"),
                        offsetTop = activeLi[0] && activeLi[0].offsetTop - (resultList.height() / 2) || 0;

                    resultList.scrollTop(offsetTop);
                }

            },
            onClickAfter: function (node, a, item, event) {

                event.preventDefault();

                var r = confirm("You will be redirected to:\n" + item.href + "\n\nContinue?");
                if (r == true) {
                    window.open(item.href);
                }

                $('#result-container').text('');

            },
            onResult: function (node, query, result, resultCount) {
                if (query === "") return;

                var text = "";
                if (result.length > 0 && result.length < resultCount) {
                    text = "Showing <strong>" + result.length + "</strong> of <strong>" + resultCount + '</strong> elements matching "' + query + '"';
                } else if (result.length > 0) {
                    text = 'Showing <strong>' + result.length + '</strong> elements matching "' + query + '"';
                } else {
                    text = 'No results matching "' + query + '"';
                }
                $('#result-container').html(text);

            },
            onMouseEnter: function (node, a, item, event) {

                if (item.group === "country") {
                    $(a).append('<span class="flag-chart flag-' + item.display.replace(' ', '-').toLowerCase() + '"></span>')
                }

            },
            onMouseLeave: function (node, a, item, event) {

                $(a).find('.flag-chart').remove();

            }
        }
    });
        

        

    


header('Content-Type: application/json');

echo json_encode(array(
    "status"    => true,
    "error"     => null,
    "data"      => array(
        "country"   => array(
                "AfghanisTan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and Barbuda",
                "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh",
                "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
                "Bosnia and Herzegovina", "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina Faso", "Burma",
                "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Republic", "Chad",
                "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic", "Congo, Republic of the",
                "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti",
                "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador",
                "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", "Gabon",
                "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Greenland", "Grenada", "Guatemala", "Guinea",
                "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India",
                "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan",
                "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kuwait", "Kyrgyzstan", "Laos",
                "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
                "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
                "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Mongolia", "Morocco", "Monaco",
                "Mozambique", "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger",
                "Nigeria", "Norway", "Oman", "Pakistan", "Panama", "Papua New Guinea", "Paraguay", "Peru",
                "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Samoa", "San Marino",
                "Sao Tome", "Saudi Arabia", "Senegal", "Serbia and Montenegro", "Seychelles", "Sierra Leone",
                "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "Spain",
                "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan",
                "Tajikistan", "Tanzania", "Thailand", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
                "Turkmenistan", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States",
                "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe"
            ),
        "capital"   => array(
            "Abu Dhabi", "Abuja", "Accra", "Adamstown", "Addis Ababa", "Algiers", "Alofi", "Amman", "Amsterdam",
            "Andorra la Vella", "Ankara", "Antananarivo", "Apia", "Ashgabat", "Asmara", "Astana", "Asunción", "Athens",
            "Avarua", "Baghdad", "Baku", "Bamako", "Bandar Seri Begawan", "Bangkok", "Bangui", "Banjul", "Basseterre",
            "Beijing", "Beirut", "Belgrade", "Belmopan", "Berlin", "Bern", "Bishkek", "Bissau", "Bogotá", "Brasília",
            "Bratislava", "Brazzaville", "Bridgetown", "Brussels", "Bucharest", "Budapest", "Buenos Aires", "Bujumbura",
            "Cairo", "Canberra", "Caracas", "Castries", "Cayenne", "Charlotte Amalie", "Chisinau", "Cockburn Town",
            "Conakry", "Copenhagen", "Dakar", "Damascus", "Dhaka", "Dili", "Djibouti", "Dodoma", "Doha", "Douglas",
            "Dublin", "Dushanbe", "Edinburgh of the Seven Seas", "El Aaiún", "Episkopi Cantonment", "Flying Fish Cove",
            "Freetown", "Funafuti", "Gaborone", "George Town", "Georgetown", "Georgetown", "Gibraltar", "King Edward Point",
            "Guatemala City", "Gustavia", "Hagåtña", "Hamilton", "Hanga Roa", "Hanoi", "Harare", "Hargeisa", "Havana",
            "Helsinki", "Honiara", "Islamabad", "Jakarta", "Jamestown", "Jerusalem", "Juba", "Kabul", "Kampala",
            "Kathmandu", "Khartoum", "Kiev", "Kigali", "Kingston", "Kingston", "Kingstown", "Kinshasa", "Kuala Lumpur",
            "Kuwait City", "Libreville", "Lilongwe", "Lima", "Lisbon", "Ljubljana", "Lomé", "London", "Luanda", "Lusaka",
            "Luxembourg", "Madrid", "Majuro", "Malabo", "Malé", "Managua", "Manama", "Manila", "Maputo", "Marigot",
            "Maseru", "Mata-Utu", "Mbabane Lobamba", "Melekeok Ngerulmud", "Mexico City", "Minsk", "Mogadishu", "Monaco",
            "Monrovia", "Montevideo", "Moroni", "Moscow", "Muscat", "Nairobi", "Nassau", "Naypyidaw", "N'Djamena",
            "New Delhi", "Niamey", "Nicosia", "Nicosia", "Nouakchott", "Nouméa", "Nukuʻalofa", "Nuuk", "Oranjestad",
            "Oslo", "Ottawa", "Ouagadougou", "Pago Pago", "Palikir", "Panama City", "Papeete", "Paramaribo", "Paris",
            "Philipsburg", "Phnom Penh", "Plymouth Brades Estate", "Podgorica Cetinje", "Port Louis", "Port Moresby",
            "Port Vila", "Port-au-Prince", "Port of Spain", "Porto-Novo Cotonou", "Prague", "Praia", "Cape Town",
            "Pristina", "Pyongyang", "Quito", "Rabat", "Reykjavík", "Riga", "Riyadh", "Road Town", "Rome", "Roseau",
            "Saipan", "San José", "San Juan", "San Marino", "San Salvador", "Sana'a", "Santiago", "Santo Domingo",
            "São Tomé", "Sarajevo", "Seoul", "Singapore", "Skopje", "Sofia", "Sri Jayawardenepura Kotte", "St. George's",
            "St. Helier", "St. John's", "St. Peter Port", "St. Pierre", "Stanley", "Stepanakert", "Stockholm", "Sucre",
            "Sukhumi", "Suva", "Taipei", "Tallinn", "Tarawa Atoll", "Tashkent", "Tbilisi", "Tegucigalpa", "Tehran",
            "Thimphu", "Tirana", "Tiraspol", "Tokyo", "Tórshavn", "Tripoli", "Tskhinvali", "Tunis", "Ulan Bator", "Vaduz",
            "Valletta", "The Valley", "Vatican City", "Victoria", "Vienna", "Vientiane", "Vilnius", "Warsaw",
            "Washington, D.C.", "Wellington", "West Island", "Willemstad", "Windhoek", "Yamoussoukro", "Yaoundé", "Yaren",
            "Yerevan", "Zagreb"
        )
    )
));
        
#form-country_v2 .typeahead__list {
    max-height: 300px;
    overflow-y: auto;
    overflow-x: hidden;
}

.project-jquerytypeahead.page-demo .typeahead__list li a {
    position: relative;
}

.project-jquerytypeahead.page-demo .result-container {
    position: absolute;
    color: #777;
    top: -1.5em;
}

.project-jquerytypeahead.page-demo .typeahead-search li a .flag-chart {
    position: absolute;
    right: 16px;
    top: 10px;
}

.flag-chart {
    position: absolute;
    right: 10px;
    top: 6px;
    width: 30px;
    height: 20px;
    line-height: 14px;
    vertical-align: text-top;
    display: inline-block;
    margin: -1px 3px -1px 0;
    background:url(/assets/jquerytypeahead/img/country_v2.png) no-repeat scroll left top transparent;
}
.flag-united-states {
    background-position: -30px top;
}
.flag-united-kingdom {
    background-position: -60px top;
}
.flag-france {
    background-position: -90px top;
}
.flag-germany {
    background-position: -120px top;
}
.flag-denmark {
    background-position: -150px top;
}
.flag-italy {
    background-position: -180px top;
}
.flag-mexico {
    background-position: -210px top;
}
.flag-brazil {
    background-position: -240px top;
}
.flag-canada {
    background-position: -270px top;
}

/* MORE FLAGS BELOW */        
Car v1
  • minLength: 1 sets the minimum character before the search result appears
  • Result list is reordered asc (Ascending)
  • offset: true will only match results that starts with the query string
  • A list of car brands are requested locally through Ajax /jquerytypeahead/country_v2.json. The object source.car.url contains properties to override the default Ajax request. A POST request will be sent with extra data myKey: myValue.
  • source.car.data will be combined with the Ajax response, press "M" and see the added car brand


    $.typeahead({
        input: '.js-typeahead-car_v1',
        minLength: 1,
        order: "asc",
        offset: true,
        hint: true,
        source: {
            car: {
                data: ["My first added brand", "M1 added brand at start"],
                ajax: {
                    type: "POST",
                    url: "/jquerytypeahead/car_v1.json",
                    data: {
                        myKey: "myValue"
                    }
                }
            }
        },
        callback: {
            onClick: function (node, a, item, event) {

                console.log(node)
                console.log(a)
                console.log(item)
                console.log(event)

                console.log('onClick function triggered');

            },
            onSubmit: function (node, form, item, event) {

                console.log(node)
                console.log(form)
                console.log(item)
                console.log(event)

                console.log('onSubmit override function triggered');

            }
        }
    });

        

        

    


header('Content-Type: application/json');

echo json_encode(
    array(
        "Acura", "Audi", "BMW", "Buick", "Cadillac", "Chevrolet", "Dodge", "Chrysler", "Ford", "GMC", "Hyunday",
        "Infinity", "Jaguar", "Jeep", "Kia Motors", "Land Rover", "Lexus", "Lincoln", "Mazda", "Mercedes-benz",
        "Mitsubishi", "Nissan", "Pontiac", "Porsche", "Saab", "Saturn", "Scion", "Subaru", "Suzuki", "Toyota",
        "Honda", "Hummer", "Mercury", "Mini", "Volkswagen", "Volvo"
    )
);        
French v1
  • The minLength: 0 and searchOnFocus: true sets the Typeahead to search for results on focus even if no query was typed.
  • The search source contains all of the french words starting by "ab".
  • accent: true means that all accents will be ignored from the search and displayed regardless of the punctuation, ex: é = e, À = a.
    Try and type "abe", you can see that the matching results can contain accents.
    If you type "é" the search results will match strings that contains "e".


    $.typeahead({
        input: '.js-typeahead-french_v1',
        minLength: 0,
        maxItem: 15,
        order: "asc",
        hint: true,
        accent: true,
        searchOnFocus: true,
        backdrop: {
            "background-color": "#3879d9",
            "opacity": "0.1",
            "filter": "alpha(opacity=10)"
        },
        source: {
            ab: "/jquerytypeahead/french_v1.json"
        },
        debug: true
    });

        

        

    


header('Content-Type" => application/json');

echo json_encode(array(
    "aberdeen-angus", "Abominablement", "abaca", "aberrance", "abominant", "abachi", "aberrant", "abomination", "aback",
    "aberration", "abomination de la désolation", "abacus", "aberration chromatique", "abominé", "abadir",
    "aberration chromosomique", "abominer", "abaissant", "aberration optique", "abondamment", "abaisse",
    "aberration sphérique", "abondance", "abaissé", "aberré", "abondance de biens ne nuit pas", "abaisse-langue",
    "abet", "abondant", "abaissement", "abêti", "abondé", "abaisser", "abêtir", "abondement", "abaisseur", "abêtissant",
    "abonder", "abajoue", "Abêtissement", "abonnant", "abalone", "abeyance", "abonné", "abalourdir", "abgal",
    "abonnement", "abamectine", "ab hoc", "abonner", "abandon", "abhor", "abonnir", "abandon de caddie", "abhorrant",
    "aboral", "abandon de créance", "abhorré", "abord", "abandon de poste", "abhorrence", "abordable", "abandonnant",
    "abhorrent", "abordage", "abandonné", "abhorrer", "abordant", "abandonner", "abide", "abordé", "abandonnique",
    "abiding", "aborder", "abaque", "abidjanais", "aborder un vaisseau ennemi", "abase", "abidjanaise", "abords",
    "abasie", "abies", "aborigène", "abasourdi", "abies alba", "aboriginal", "abasourdir", "abies fraseri", "aborigine",
    "abasourdissant", "abies numidica", "abornement", "abat", "abiétacée", "aborner", "abatage", "ability", "abort",
    "abâtardi", "abîmant", "abortif", "abâtardir", "abîme", "abortion", "abâtardissant", "abîmé", "abortive", "abate",
    "abimer", "abot", "abatellement", "abîmer", "abouchant", "abatement", "abouché", "abat-faim",
    "abiogenèse", "aboucher", "abatis", "abiose", "aboulant", "abat-jour", "abiotique", "aboulé", "abator", "ABIR",
    "abouler", "abats", "ab irato", "aboulie", "abat-son", "abject", "aboulique", "Abattable", "Abjectement", "abound",
    "abattage", "abjection", "about", "abattant", "abjurant", "aboutage", "abatte", "Abjuration", "aboutant",
    "abattement", "abjuratoire", "abouté", "abattement fiscal", "abjure", "aboutement", "Abatteur", "abjuré", "abouter",
    "abattis", "abjurer", "about-face", "abattoir", "abkhaze", "abouti", "abattre", "ablactation", "aboutir", "abattu",
    "ablatant", "aboutissant", "abattue", "ablaté", "aboutissants", "Abat-vent", "ablatif", "aboutissement", "abat-voix",
    "ablation", "above", "abave", "ablatir", "aboveboard", "abaxial", "ablative", "Above the line", "abbasside",
    "ablativo", "aboyant", "abbatial", "ablaze", "aboyé", "abbatiale", "able", "aboyer", "abbatiat", "ablégat",
    "aboyeur", "abbaye", "ablégation", "Abracadabra", "Abbaye de Westminster", "ableret", "abracadabrant", "abbé",
    "ablet", "abracadabresque", "abbess", "ablette", "abradant", "abbesse", "ablier", "abrasant", "abbevillien",
    "abloquant", "abrasé", "abbey", "abloqué", "abraser", "abbot", "abluant", "abrasif", "abbreviation", "abluer",
    "abrasimètre", "abc", "ablution", "abrasion", "abcès", "ablutions", "abrasive", "Abcès dentaire", "ablutophobie",
    "abréaction", "ABD", "ably", "abréagir", "abdicate", "abnegation", "abreast", "abdication", "abnégation", "abrégé",
    "abdiquant", "abnormal", "abrégeant", "abdiqué", "abnormality", "abrégement", "abdiquer", "abnormally", "abrègement",
    "abdomen", "aboard", "abrégément", "abdominal", "abode", "abréger", "abdominaux", "aboi", "abreuvage", "abduct",
    "aboiement", "abreuvant", "abducteur", "abois", "abreuvé", "abduction", "aboli", "Abreuvement", "abductor", "abolir",
    "abreuver", "abécédaire", "abolish", "abreuvoir", "abée", "abolissant", "abréviatif", "abeillage", "abolissement",
    "abréviation", "abeille", "abolition", "abréviativement", "abeille charpentière", "abolitionism", "abréviature",
    "abeiller", "abolitionist", "abrévié", "abeillère", "abolitionnisme", "abri", "abélien", "Abolitionniste", "abribus",
    "abelisaurus", "abomasum", "abricot", "aber", "abominable", "abricotant", "abricoté", "abricoter", "abricotier",
    "abricotier du japon", "abricot sec", "abrictosaurus", "abri de jardin", "abridge", "abrier", "abri météorologique",
    "abri-sous-roche", "abritant", "abrité", "abriter", "abrivent", "abroad", "abrogate", "abrogatif", "abrogation",
    "abrogé", "abrogeable", "abrogeant", "abroger", "abronia graminea", "abrosaurus", "abrouti", "abroutir", "abrupt",
    "abruptement", "abruptly", "abruti", "abrutir", "abrutissant", "abrutissement", "abrutisseur", "ABS", "ABSA",
    "abscess", "abscissa", "abscisse", "abscission", "abscond", "absconder", "absconding", "abscons", "absconse",
    "abseil", "abseiling", "absence", "absent", "absentant", "absenté", "absentee", "absenteeism", "absentéisme",
    "absentéiste", "absenter", "absentia", "absidal", "abside", "absidial", "absidiole", "absinth", "absinthe",
    "absinthé", "absolu", "absoluité", "absolument", "absolute", "absolutely", "absolutif", "absolution", "absolutism",
    "absolutisme", "absolutist", "absolutiste", "absolutoire", "absolvant", "absolve", "absorb", "absorbable",
    "absorbant", "absorbé", "absorbement", "absorbent", "absorber", "absorbeur", "Absorbeur de vapeurs d'essence",
    "absorptiométrie", "absorption", "absorption intestinale", "absorption racinaire", "absorptivité", "absoudre",
    "absous", "absoute", "abstain", "abstème", "abstemious", "abstenant", "abstention", "abstentionnisme",
    "abstentionniste", "abstenu", "abstergent", "absterger", "abstersif", "abstersion", "abstinence", "abstinent",
    "abstracteur", "abstractif", "abstraction", "abstractivement", "abstraire", "abstrait", "abstraitement",
    "abstrayant", "abstrus", "abstruse", "absurd", "absurde", "absurdement", "absurdité", "absurdity", "abundance",
    "abundant", "abundantly", "abus", "abusant", "abus de bien social", "abus de biens sociaux", "abus de confiance",
    "abus de droit", "abus de faiblesse", "abus de langage", "abus de majorité", "abus de minorité", "abuse", "abusé",
    "abuser", "abuser d'une personne", "abuseur", "abusif", "abusive", "abusivement", "abusus", "abut", "abuter",
    "abutilon", "abutment", "abyme", "abysmal", "abyss", "abyssal", "abysse", "abyssin", "Abyssinian", "abyssinien", "abyssinienne"
));        

Advanced demos

Beer v1
  • Changed maxItem: 15 to display more items inside the result list
  • Changed maxItemPerGroup: 5 to display a limited set of results per group
  • href: "/beers/{{group}}/{{display}}/" sets a custom link to every result item. Use "{{itemKey}}" to replace by value
  • Custom backdrop, any CSS can be set to customize the backdrop
  • There are 4 different list to search into, each list has a unique name and location
  • If you are providing only an url inside the source list, it can be simplified by removing 1 dimension
  • The result is group by list name, type "blonde" to see results from multiple groups
  • The dropdownFilter is enabled creating filtering options for groups by default.
  • href callback changes the window location


    $.typeahead({
        input: '.js-typeahead-beer_v1',
        minLength: 1,
        maxItem: 15,
        order: "asc",
        hint: true,
        group: {
            template: "{{group}} beers!"
        },
        maxItemPerGroup: 5,
        backdrop: {
            "background-color": "#fff"
        },
        href: "/beers/{{group|slugify}}/{{display|slugify}}/",
        dropdownFilter: "all beers",
        emptyTemplate: 'No result for "{{query}}"',
        source: {
            "ale": {
                ajax: {
                    url: "/jquerytypeahead/beer_v1.json",
                    path: "data.beer.ale"
                }
            },
            "lager": {
                ajax: {
                    url: "/jquerytypeahead/beer_v1.json",
                    path: "data.beer.lager"
                }
            },
            "stout and porter": {
                ajax: {
                    url: "/jquerytypeahead/beer_v1.json",
                    path: "data.beer.stout"
                }
            },
            "malt": {
                ajax: {
                    url: "/jquerytypeahead/beer_v1.json",
                    path: "data.beer.malt"
                }
            }
        },
        callback: {
            onClickAfter: function (node, a, item, event) {

                event.preventDefault;

                // href key gets added inside item from options.href configuration
                alert(item.href);

            }
        },
        debug: true
    });

        

        

    


header('Content-Type: application/json');

echo json_encode(array(
    "status" => true,
    "error"  => null,
    "data"   => array(
        "beer"   => array(
            "ale"   => array(
                "Affligem Blonde", "Amsterdam Big Wheel", "Amsterdam Boneshaker IPA", "Amsterdam Downtown Brown", "Amsterdam Oranje Summer White",
                "Anchor Liberty Ale", "Beaus Lug Tread Lagered Ale", "Beerded Lady", "Belhaven Best Ale", "Big Rock Grasshopper Wheat",
                "Big Rock India Pale Ale", "Big Rock Traditional Ale", "Big Rock Warthog Ale", "Black Oak Nut Brown Ale", "Black Oak Pale Ale",
                "Boddingtons Pub Ale", "Boundary Ale", "Caffreys", "Camerons Auburn Ale", "Camerons Cream Ale", "Camerons Rye Pale Ale", "Ceres Strong Ale",
                "Cheval Blanc", "Crazy Canuck Pale Ale", "Creemore Springs Altbier", "Crosswind Pale Ale", "De Koninck", "Delirium Tremens",
                "Erdinger Dunkel Weissbier", "Erdinger Weissbier", "Export", "Flying Monkeys Amber Ale", "Flying Monkeys Antigravity",
                "Flying Monkeys Hoptical", "Flying Monkeys Netherworld", "Flying Monkeys Smashbomb", "Fruli", "Fullers Extra Spec Bitter",
                "Fullers London Pride", "Granville English Bay Pale", "Granville Robson Hefeweizen", "Griffon Pale Ale", "Griffon Red Ale",
                "Hacker-Pschorr Hefe Weisse", "Hacker-Pschorr Munchen Gold", "Hockley Dark Ale", "Hoegaarden", "Hops & Robbers IPA", "Houblon Chouffe",
                "James Ready Original Ale", "Kawartha Cream Ale", "Kawartha Nut Brown Ale", "Kawartha Premium Pale Ale", "Kawartha Raspberry Wheat",
                "Keiths", "Keiths Cascade Hop Ale", "Keiths Galaxy Hop Ale", "Keiths Hallertauer Hop Ale", "Keiths Hop Series Mixer",
                "Keiths Premium White", "Keiths Red", "Kilkenny Cream Ale", "Konig Ludwig Weissbier", "Kronenbourg 1664 Blanc", "La Chouffe",
                "La Messager Red Gluten Free", "Labatt 50 Ale", "Labatt Bass Pale Ale", "Lakeport Ale", "Leffe Blonde", "Leffe Brune",
                "Legendary Muskoka Oddity", "Liefmans Fruitesse", "Lions Winter Ale", "Maclays", "Mad Tom IPA", "Maisels Weisse Dunkel",
                "Maisels Weisse Original", "Maredsous Brune", "Matador 2.0 El Toro Bravo", "Mcauslan Apricot Wheat Ale", "Mcewans Scotch Ale",
                "Mill St Belgian Wit", "Mill St Coffee Porter", "Mill St Stock Ale", "Mill St Tankhouse Ale", "Molson Stock Ale", "Moosehead Pale Ale",
                "Mort Subite Kriek", "Muskoka Cream Ale", "Muskoka Detour IPA", "Muskoka Harvest Ale", "Muskoka Premium Dark Ale", "Newcastle Brown Ale",
                "Niagaras Best Blonde Prem", "Okanagan Spring Pale Ale", "Old Speckled Hen", "Ommegang Belgian Pale Ale", "Ommegang Hennepin", "PC IPA",
                "Palm Amber Ale", "Petrus Blonde", "Petrus Oud Bruin Aged Red", "Publican House Ale", "Red Cap", "Red Falcon Ale", "Rickards Dark",
                "Rickards Original White", "Rickards Red", "Rodenbach Grand Cru", "Schofferhofer Hefeweizen", "Shock Top Belgian White",
                "Shock Top Raspberry Wheat", "Shock Top Variety Pack", "Sleeman Cream Ale", "Sleeman Dark", "Sleeman India Pale Ale", "Smithwicks Ale",
                "Spark House Red Ale", "St. Ambroise India Pale Ale", "St. Ambroise Oatmeal Stout", "St. Ambroise Pale Ale", "Stereovision Kristall Wheat",
                "Stone Hammer Dark Ale", "Sunny & Share Citrus Saison", "Tetleys English Ale", "Thirsty Beaver Amber Ale", "True North Copper Altbier",
                "True North Cream Ale", "True North India Pale Ale", "True North Strong", "True North Wunder Weisse", "Twice As Mad Tom IPA",
                "Unibroue La Fin Du Monde", "Unibroue Maudite", "Unibroue Trois Pistoles", "Upper Canada Dark Ale", "Urthel Hop-It Tripel IPA",
                "Waterloo IPA", "Weihenstephan Kristalweiss", "Wellington Arkell Best Bitr", "Wellington County Dark Ale", "Wellington Special Pale", "Wells IPA"
            ),
            "lager" => array(
                "AC-DC Premium Lager", "Alpine Lager", "Amstel Light", "Amsterdam (416) Local Lager", "Amsterdam Natural Blonde", "Anchor Steam Beer",
                "Barking Squirrel Lager", "Bavaria 8.6", "Bavaria 8.6 Red", "Bavaria Grapefruit Radler", "Bavaria Premium Beer", "Bavik Pils",
                "Baysville Rock Cut Lager", "Becks", "Belle Gueule", "Big Rock Brewmasters Selection", "Big Rock Light Lime", "Big Rock Saaz Republic Pilz",
                "Birra Castello", "Birra Moretti", "Bitburger", "Black Ice", "Black Label", "Blue", "Blue Light", "Bohemian", "Boris Beer",
                "Boris Bold Strong Beer", "Boxer Ice", "Boxer Lager", "Brava", "Brava 5.5", "Brava Light", "Brouczech Premium Lager", "Bud Light",
                "Bud Light Lime", "Bud Light Lime Labatt", "Bud Light Platinum", "Budweiser", "Budweiser Crown", "Budweiser Shot Labatt", "Busch Ice",
                "Busch Lager", "Busch Light", "Camerons Dark266", "Camerons Lager", "Canadian", "Canadian 67", "Canadian 67 Sublime", "Canadian Coldshots",
                "Carib Lager", "Carling Ice", "Carling Lager", "Carling Light", "Carlsberg", "Carlsberg Lite", "Cool Beer Lager", "Coors Banquet", "Coors Light",
                "Corona", "Corona Light", "Cracked Canoe", "Creemore Collection", "Creemore Kellerbier", "Creemore Lager", "Creemore Springs Combo Pack",
                "Creemore Trad Pilsner", "Creemore Urbock", "Crest Super", "Crystal", "Czechvar", "Dab Maibock", "Dab Original Lager", "Dead Frog Mixed Pack",
                "Desperados Tequila Beer", "Dos Equis Amber", "Dos Equis Lager", "Dunkel Weihenstephaner", "Faxe Amber Lager", "Faxe Extra Strong - 10",
                "Faxe Premium Lager - 5", "Faxe Red", "Faxe Strong", "Formosa Springs Draft", "Fosters Import", "Fuerstenberg Prem Pilsener", "Get2gether",
                "Granville Summer Mingler", "Grolsch Lager 450ml", "Grolsch Premium Lager", "Guinness Black Lager", "Hacker-Pschorr Kellerbier", "Harbin Beer",
                "Harp Lager", "Heineken", "Henninger Premium Lager", "Hockley Taster Pack", "Hofbraeu Muenchen Original", "Hogsback Vintage Lager",
                "Hollandia Pilsner", "Holsten Festbock", "Holsten Maibock", "Holsten Premium Bier", "Hopf Weisse", "Hops Bolts India Pale Lager",
                "James Ready 5.5", "James Ready Ice 6.0", "James Ready Lager", "James Ready Light", "Jever Pilsener", "Keiths Brewmaster", "Keiths Light",
                "Keystone Ice", "Keystone Lager", "Keystone Light", "King Brewery Dark Lager", "King Brewery Pilsner", "King Brewery Vienna Lager", "Kokanee",
                "Kozel", "Krombacher Dark", "Krombacher Pils", "Krombacher Weizen", "Kronenbourg 1664", "La Tabachera", "Labatt Extra Dry", "Labatt Genuine Lager",
                "Labatt Ice", "Lakeport Honey Lager", "Lakeport Ice", "Lakeport Light", "Lakeport Pilsener", "Lakeport Red", "Laker Extra Ice", "Laker Honey",
                "Laker Ice", "Laker Lager", "Laker Light", "Laker Red", "Laker Strong", "Lech Beer", "Lowenbrau", "Lucky Lager", "Maximum Ice", "Menabrea Blonda",
                "Michelob Ultra", "Mill St Original Organic", "Millennium Buzz Hemp Beer", "Miller Chill Domestic", "Miller Chill Import",
                "Miller Genuine Draft Clear", "Molson Canadian Wheat", "Molson Dry", "Molson M", "Molson XXX", "Mongozo Premium Pilsner", "Moosehead Lager",
                "Moosehead Light", "Moosehead Light Lime", "Moskato Life", "Moskato Life Rose", "Muskoka Craft Lager", "Muskoka Summer Weiss",
                "Muskoka Survival Pack", "Mythos Beer", "Negra Modelo", "Neustadt Lager", "Octane 7.0", "Okanagan Craft Pack", "Okanagan Springs 1516 Lager",
                "Okocim Pilsner", "Old Milwaukee", "Old Milwaukee", "Old Milwaukee Ice", "Old Milwaukee Light", "Old Style Pilsner", "Old Vienna",
                "PC Black Lager", "PC Cerveza", "PC Down Under Amber", "PC Dry", "PC Genuine Lager", "PC Honey Red", "PC Light", "PC Low Carb", "PC Plznr",
                "Pabst Blue Ribbon", "Pabst Blue Ribbon 5.9", "Pabst Blue Ribbon Light", "Paulaner Hefe-Weissbier", "Pedavena Birra Dolomiti",
                "Peroni Nastro Azzuro", "Pilsner Urquell", "Pistonhead Kustom Lager", "Poppers Party Pack", "Prison Break Pilsner", "Radeberger Pilsner",
                "Red Baron", "Red Baron Light", "Red Baron Lime", "Red Baron Platinum Light", "Red Bull", "Red Stripe", "Rickards Blonde", "Rickards Cardigan",
                "Rickards Fall Taster", "Rickards Lederhosen", "Rickards Oakhouse", "Rickards Shandy", "Rickards Summer Taster Pack", "Rickards Taster Pack",
                "Rickards Winter Taster Pack", "Rolling Rock Pale Lager", "Rosarda Rose", "Saint Andre", "Samuel Adams Boston Lager", "San Miguel Premium Lager",
                "Sapporo", "Schnitzerbrau Gluten Free Lager", "Schofferhofer Grapefruit Radlr", "Seagram Mixer Pack", "Shock Top Lemon Shandy", "Sleeman Clear 2.0",
                "Sleeman Honey Brown Lager", "Sleeman Light", "Sleeman Original Draught", "Sleeman Seasonal Selections", "Sleeman Selections",
                "Sleeman Silver Creek Lager", "Sol", "Spaten", "St Ambroise Premium Taster", "Staropramen", "Steam Whistle", "Steeler", "Stella Artois",
                "Stella Legere", "Stiegl Bier", "Stiegl Grapefruit Radler", "Stone Hammer Pilsner", "Stonewall Light", "Tecate", "Tennents Export Lager",
                "Thurn Taxis Lager", "Thurn Taxis Pilsener", "Thurn Taxis Wolfgang Dunkl", "Tiger Beer", "Trailhead Premium Lager", "True North Blonde Lager",
                "Tuborg Gold", "Tuborg Pilsner", "Tyskie", "Unibroue Blanche Dechambly", "Upper Canada Lager", "Warsteiner Premium Dunkel", "Warsteiner Premium Verum",
                "Waterloo Amber Lager", "Waterloo Dark", "Waterloo Grapefruit Radler", "Waterloo Kolsch Sampler", "Waterloo Pilsner", "Weihenstephan Vitus",
                "Weihenstephaner Hefeweiss", "Wernesgruner Pils", "Winter Mingler", "Wolfgangs German Style Beer", "Xingu Black Beer", "Yanjing Beer", "Zywiec Beer"
            ),
            "stout" => array(
                "Belhaven Black Scottish Stout", "Guinness Draught Bottle", "Guinness Extra Stout", "Guinness Pub Draught", "Murphys Irish Stout",
                "Muskoka Chocolate Cranberry", "Sleeman Fine Porter"
            ),
            "malt" => array(
                "Boxer Watermelon", "Bud Light Lime Lime-a-rita", "Bud Light Lime Mang-o-rita", "Bud Light Lime Straw-ber-rita", "Colt 45",
                "DJ Trotters Flirty Daiquiri", "DJ Trotters Lolita", "Four Loko Black Cherry", "Four Loko Fruit Punch", "Four Loko Grape", "Four Loko Lemonade",
                "Four Loko Peach", "Four Loko Watermelon", "Kensington Watermelon Wheat", "Mad Jack", "Mickeys", "Mojo Fruit Punch", "Mojo Shot Blue Lagoon",
                "Mojo Shot Melon Ball", "Mojo Shot Sourberry", "Mojo Strawberry & Kiwi", "Mons Abbey Blonde", "Mons Abbey Witte", "Olde English 800",
                "Pepito Sangria", "Poppers Cran Ice", "Poppers Hard Ice", "Poppers Orange Smoothie", "Poppers Pink", "Poppers Ricco Sangria", "Poppers Wild Ice",
                "Seagram Iced Lemon Tea", "Seagram Lemon Lime", "Seagram Orange Mango", "Seagram Wildberry", "Seagram Wildberry Extra 6.9", "Twisted Tea", "Wellington Iron Duke"
            )
        )
    )
));        
Beer v2
  • A custom groupTemplate is used, the items will appear in a <table>
  • A function is used inside the group.template to remove the underscore from the group name
  • Since the same URL is being queried, the request will only be done once. The ajax.path configuration will then resolve to get the proper data.


    $.typeahead({
        input: '.js-typeahead-beer_v2',
        minLength: 0,
        maxItem: 15,
        order: "asc",
        hint: true,
        searchOnFocus: true,
        group: {
            template: function (item) {
                return item.group.replace(/_/g, ' ') + ' beers';
            }
        },
        maxItemPerGroup: 3,
        backdrop: {
            "background-color": "#fff"
        },
        href: "/beers/{{group|slugify}}/{{display|slugify}}/",
        emptyTemplate: 'No result for "{{query}}"',
        template: '<div class="beer-card">' +
        '<div class="beer-card__image">' +
        '<img src="/assets/jquerytypeahead/img/beer_v2/{{group}}/{{display|raw|slugify}}.jpg">' +
        '</div>' +
        '<div class="beer-card__name">{{display}}</div>' +
        '</div>',
        groupTemplate: "<table><tr><td>{{group}}</td></tr></table>",
        correlativeTemplate: true,
        source: {
            "crisp_clean": {
                ajax: {
                    url: "/jquerytypeahead/beer_v2.json",
                    path: "data.beer.crisp_clean"
                }
            },
            "dark_roasty": {
                ajax: {
                    url: "/jquerytypeahead/beer_v2.json",
                    path: "data.beer.dark_roasty"
                }
            },
            "fruity_spicy": {
                ajax: {
                    url: "/jquerytypeahead/beer_v2.json",
                    path: "data.beer.fruity_spicy"
                }
            },
            "hoppy_bitter": {
                ajax: {
                    url: "/jquerytypeahead/beer_v2.json",
                    path: "data.beer.hoppy_bitter"
                }
            },
            "malty_sweet": {
                ajax: {
                    url: "/jquerytypeahead/beer_v2.json",
                    path: "data.beer.malty_sweet"
                }
            }
        },
        debug: true
    });

        

        

    


header('Content-Type: application/json');

echo json_encode(array(
    "status" => true,
    "error" => null,
    "data" => array(
        "beer" => array(
            "crisp_clean" => array(
                "American Amber Ale", "American Amber Lager", "American Cream Ale", "American Lager", "American Wheat", "Blonde Ale", "Bohemian-Style Pilsener", "European-Style Export", "German-Style Helles", "German-Style Kolsch", "German-Style Pilsener", "Vienna-Style Lager"
            ),
            "dark_roasty" => array(
                "American Imperial Porter", "American Imperial Stout", "American Stout", "Baltic-Style Porter", "Chocolate Beer", "Coffee Beer", "English-Style Brown Porter", "English-Style Oatmeal Stout", "English-Style Sweet Stout (Milk Stout)", "German-Style Brown/Altbier", "German-Style Dunkel", "German-Style Schwarzbier", "Irish-Style Dry Stout", "Robust Porter", "Smoke Porter"
            ),
            "malty_sweet" => array(
                "American Brown Ale", "American-Style Wheat Wine Ale", "British-Style Barley Wine Ale", "English-Style Brown Ale", "English-Style dark Mild", "English-Style Old Ale", "English-Style Pale Ale/ESB", "German-Style Bock", "German-Style Doppelbock", "German-Style Dunkelweizen", "German-Style Maibock", "German-Style Marzen/Oktoberfest", "German-Style Weizenbock", "Gluten Free", "Honey Beer", "Irish-Style Red", "Pumpkin Beer", "Rye Beer", "Scotch Ale/Wee Heavy", "Scottish-Style Ale", "Smoke Beer"
            ),
            "hoppy_bitter" => array(
                "American Barley Wine", "American Black Ale", "American Imperial Red Ale", "American India Pale Ale/IPA", "American Pale Ale", "English-Style Bitter", "California Common", "English-Style India Pale Ale/IPA", "Imperial India Pale Ale"
            ),
            "fruity_spicy" => array(
                "Belgian-Style Blonde Ale", "Belgian-Style Dubbel", "Belgian-Style Golden Strong Ale", "Belgian-Style Pale Ale", "Belgian-Style Quadrupel", "Belgian-Style Saison", "Belgian-Style Tripel", "Belgian-Style Witbier", "French-Style Biere de Garde", "Fruit and Field Beer", "German-Style Hefeweizen", "Herb and Spice Beer"
            )
        ),
        "glossary" => array(

        )
    )
));        
#form-beer_v2 .typeahead__list {
    background: #000;
}

#form-beer_v2 .typeahead__list td {
    padding: 10px;
    border-left: solid 1px #333;
}

#form-beer_v2 .beer-card {
    position: relative;
}

#form-beer_v2 .beer-card__name {
    position: absolute;
    bottom: 0;
    font-weight: bold;
    width: 100%;
    padding: 5px;
    background: rgba(255, 255, 255, .25);
    text-shadow: rgb(3, 3, 3) 0 0 10px;
}

#form-beer_v2 .typeahead__group {
    border-bottom: solid 1px #333;
    padding-bottom: 10px;
}

#form-beer_v2 .typeahead__group,
#form-beer_v2 .typeahead__item {
    text-align: center;
}

#form-beer_v2 .typeahead__group a {
    color: #fff;
    font-size: 20px;
    text-transform: capitalize;
}

#form-beer_v2 .typeahead__item a {
    font-size: 15px;
    text-transform: capitalize;
    display: block;


}

#form-beer_v2 .typeahead__item a:hover img {
    opacity: .6;
}        
User v1
  • dynamic: true means that the source will be fetched on input event. When dynamic is enabled, caching and compression will not be possible.
  • To prevent requests on every input change, delay: 500 (in miliseconds) is configured. The requests will be triggered 500 milliseconds after the last input event ONLY if no other event is triggered.
  • A custom PHP file is hardcoded to simulates a database search. The PHP should only output your search result as a json object.
  • template is used to build a custom template for every search results. Every words between {{variable}} will be replaced by the search result's value that corresponds to that key.
  • The query string typed inside the search input can be sent inside the ajax request using {{query}}.
  • Open your console (F12), go on Network tab, filter by XHR, type letters and see the requests coming in.
  • source.user.ajax.callback.done is used to process the data (could filter out some results) before it gets parsed. The "status" key is added inside result items.
  • Each of the 2 groups (user and project) have different display and href configurations


    $.typeahead({
        input: '.js-typeahead-user_v1',
        minLength: 1,
        order: "asc",
        dynamic: true,
        delay: 500,
        backdrop: {
            "background-color": "#fff"
        },
        template: function (query, item) {

            var color = "#777";
            if (item.status === "owner") {
                color = "#ff1493";
            }

            return '<span class="row">' +
                '<span class="avatar">' +
                    '<img src="{{avatar}}">' +
                "</span>" +
                '<span class="username">{{username}} <small style="color: ' + color + ';">({{status}})</small></span>' +
                '<span class="id">({{id}})</span>' +
            "</span>"
        },
        emptyTemplate: "no result for {{query}}",
        source: {
            user: {
                display: "username",
                href: "https://www.github.com/{{username|slugify}}",
                data: [{
                    "id": 415849,
                    "username": "an inserted user that is not inside the database",
                    "avatar": "https://avatars3.githubusercontent.com/u/415849",
                    "status":  "contributor"
                }],
                ajax: function (query) {
                    return {
                        type: "GET",
                        url: "/jquerytypeahead/user_v1.json",
                        path: "data.user",
                        data: {
                            q: "{{query}}"
                        },
                        callback: {
                            done: function (data) {
                                for (var i = 0; i < data.data.user.length; i++) {
                                    if (data.data.user[i].username === 'running-coder') {
                                        data.data.user[i].status = 'owner';
                                    } else {
                                        data.data.user[i].status = 'contributor';
                                    }
                                }
                                return data;
                            }
                        }
                    }
                }

            },
            project: {
                display: "project",
                href: function (item) {
                    return '/' + item.project.replace(/\s+/g, '').toLowerCase() + '/documentation/'
                },
                ajax: [{
                    type: "GET",
                    url: "/jquerytypeahead/user_v1.json",
                    data: {
                        q: "{{query}}"
                    }
                }, "data.project"],
                template: '<span>' +
                    '<span class="project-logo">' +
                        '<img src="{{image}}">' +
                    '</span>' +
                    '<span class="project-information">' +
                        '<span class="project">{{project}} <small>{{version}}</small></span>' +
                        '<ul>' +
                            '<li>{{demo}} Demos</li>' +
                            '<li>{{option}}+ Options</li>' +
                            '<li>{{callback}}+ Callbacks</li>' +
                        '</ul>' +
                    '</span>' +
                '</span>'
            }
        },
        callback: {
            onClick: function (node, a, item, event) {

                // You can do a simple window.location of the item.href
                alert(JSON.stringify(item));

            },
            onSendRequest: function (node, query) {
                console.log('request is sent')
            },
            onReceiveRequest: function (node, query) {
                console.log('request is received')
            }
        },
        debug: true
    });

        

        

    


//sleep(1);

$query = (!empty($_GET['q'])) ? strtolower($_GET['q']) : null;

if (!isset($query)) {
    die('Invalid query.');
}

$status = true;
$databaseUsers = array(
    array(
        "id"        => 4152589,
        "username"  => "TheTechnoMan",
        "avatar"    => "https://avatars2.githubusercontent.com/u/4152589"
    ),
    array(
        "id"        => 7377382,
        "username"  => "running-coder",
        "avatar"    => "https://avatars3.githubusercontent.com/u/7377382"
    ),
    array(
        "id"        => 748137,
        "username"  => "juliocastrop",
        "avatar"    => "https://avatars3.githubusercontent.com/u/748137"
    ),
    array(
        "id"        => 619726,
        "username"  => "cfreear",
        "avatar"    => "https://avatars0.githubusercontent.com/u/619726"
    ),
    array(
        "id"        => 5741776,
        "username"  => "solevy",
        "avatar"    => "https://avatars3.githubusercontent.com/u/5741776"
    ),
    array(
        "id"        => 906237,
        "username"  => "nilovna",
        "avatar"    => "https://avatars2.githubusercontent.com/u/906237"
    ),
    array(
        "id"        => 612578,
        "username"  => "Thiago Talma",
        "avatar"    => "https://avatars2.githubusercontent.com/u/612578"
    ),
    array(
        "id"        => 2051941,
        "username"  => "webcredo",
        "avatar"    => "https://avatars2.githubusercontent.com/u/2051941"
    ),
    array(
        "id"        => 985837,
        "username"  => "ldrrp",
        "avatar"    => "https://avatars2.githubusercontent.com/u/985837"
    ),
    array(
        "id"        => 1723363,
        "username"  => "dennisgaudenzi",
        "avatar"    => "https://avatars2.githubusercontent.com/u/1723363"
    ),
    array(
        "id"        => 2649000,
        "username"  => "i7nvd",
        "avatar"    => "https://avatars2.githubusercontent.com/u/2649000"
    ),
    array(
        "id"        => 2757851,
        "username"  => "pradeshc",
        "avatar"    => "https://avatars2.githubusercontent.com/u/2757851"
    )
);

$resultUsers = [];
foreach ($databaseUsers as $key => $oneUser) {
    if (strpos(strtolower($oneUser["username"]), $query) !== false ||
        strpos(str_replace('-', '', strtolower($oneUser["username"])), $query) !== false ||
        strpos(strtolower($oneUser["id"]), $query) !== false) {
        $resultUsers[] = $oneUser;
    }
}

$databaseProjects = array(
    array(
        "id"        => 1,
        "project"   => "jQuery Typeahead",
        "image"     => "http://www.runningcoder.org/assets/jquerytypeahead/img/jquerytypeahead-preview.jpg",
        "version"   => "1.7.0",
        "demo"      => 10,
        "option"    => 23,
        "callback"  => 6,
    ),
    array(
        "id"        => 2,
        "project"   => "jQuery Validation",
        "image"     => "http://www.runningcoder.org/assets/jqueryvalidation/img/jqueryvalidation-preview.jpg",
        "version"   => "1.4.0",
        "demo"      => 11,
        "option"    => 14,
        "callback"  => 8,
    )
);

$resultProjects = [];
foreach ($databaseProjects as $key => $oneProject) {
    if (strpos(strtolower($oneProject["project"]), $query) !== false) {
        $resultProjects[] = $oneProject;
    }
}

// Means no result were found
if (empty($resultUsers) && empty($resultProjects)) {
    $status = false;
}

header('Content-Type: application/json');

echo json_encode(array(
    "status" => $status,
    "error"  => null,
    "data"   => array(
        "user"      => $resultUsers,
        "project"   => $resultProjects
    )
));        
.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .row {
    display: table-row;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .row  > * {
    display: table-cell;
    vertical-align: middle;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .username {
    padding: 0 10px;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .id {
    font-size: 12px;
    color: #777;
    font-variant: small-caps;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .avatar img {
    height: 26px;
    width: 26px;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .project-logo {
    display: inline-block;
    height: 100px;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .project-logo img {
    height: 100%;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .project-information {
    display: inline-block;
    vertical-align: top;
    padding: 20px 0 0 20px;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .project-information > span {
    display: block;
    margin-bottom: 5px;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result > ul > li > a small {
    padding-left: 0px;
    color: #999;
}

.project-jquerytypeahead.page-demo #form-user_v1 .typeahead__result .project-information li {
    font-size: 12px;
}        
Hockey v1
  • Using options.template to build result list. The {{variable}} will be replaced by the result object matching key
  • cache: true will set the Ajax request result inside localStorage
  • Custom grouping group: "division" is using the result object key instead of the source list
  • display: ["name", "city", "division"] allows the Typeahead to search inside these 3 object keys for any results
  • While groups are sets on "division", the dropdownFilter is set to filter teams based on conference.
  • correlativeTemplate: true enables the search text to match any word, anywhere inside the template separated by spaces


    $.typeahead({
        input: '.js-typeahead-hockey_v1',
        minLength: 1,
        maxItem: 8,
        maxItemPerGroup: 6,
        order: "asc",
        hint: true,
        cache: true,
        group: {
            key: "division",
            template: function (item) {

                var division = item.division;
                if (~division.toLowerCase().indexOf('north')) {
                    division += " ---> Snow!";
                } else if (~division.toLowerCase().indexOf('south')) {
                    division += " ---> Beach!";
                }

                return division;
            }
        },
        display: ["name", "city", "division"],
        dropdownFilter: [{
            key: 'conference',
            template: '<strong>{{conference}}</strong> Conference',
            all: 'All Conferences'
        }],
        template: '<span>' +
            '<span class="name">{{name}}</span>' +
            '<span class="division">({{city}}, {{division}} division, {{conference}} conference)</span>' +
            '<span class="team-logo">' +
                '<img src="/assets/jquerytypeahead/img/hockey_v1/{{img}}.gif">' +
            '</span>' +
        '</span>',
        correlativeTemplate: true,
        source: {
            teams: {
                url: "/jquerytypeahead/hockey_v1.json"
            }
        }
    });

        

        

    


header('Content-Type" => application/json');

echo json_encode(array(
    array(
        "name"          => "Ducks",
        "img"           => "ducks",
        "city"          => "Anaheim",
        "id"            => "ANA",
        "conference"    => "Western",
        "division"      => "Pacific"
    ),
    array(
        "name"          => "Thrashers",
        "img"           => "thrashers",
        "city"          => "Atlanta",
        "id"            => "ATL",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    ),
    array(
        "name"          => "Bruins",
        "img"           => "bruins",
        "city"          => "Boston",
        "id"            => "BOS",
        "conference"    => "Eastern",
        "division"      => "Northeast"
    ),
    array(
        "name"          => "Sabres",
        "img"           => "sabres",
        "city"          => "Buffalo",
        "id"            => "BUF",
        "conference"    => "Eastern",
        "division"      => "Northeast"
    ),
    array(
        "name"          => "Flames",
        "img"           => "flames",
        "city"          => "Calgary",
        "id"            => "CGY",
        "conference"    => "Western",
        "division"      => "Northwest"
    ),
    array(
        "name"          => "Hurricanes",
        "img"           => "hurricanes",
        "city"          => "Carolina",
        "id"            => "CAR",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    ),
    array(
        "name"          => "Blackhawks",
        "img"           => "blackhawks",
        "city"          => "Chicago",
        "id"            => "CHI",
        "conference"    => "Western",
        "division"      => "Central"
    ),
    array(
        "name"          => "Avalanche",
        "img"           => "avalanche",
        "city"          => "Colorado",
        "id"            => "COL",
        "conference"    => "Western",
        "division"      => "Northwest"
    ),
    array(
        "name"          => "Bluejackets",
        "img"           => "bluejackets",
        "city"          => "Columbus",
        "id"            => "CBJ",
        "conference"    => "Western",
        "division"      => "Central"
    ),
    array(
        "name"          => "Stars",
        "img"           => "stars",
        "city"          => "Dallas",
        "id"            => "DAL",
        "conference"    => "Western",
        "division"      => "Pacific"
    ),
    array(
        "name"          => "Red Wings",
        "img"           => "redwings",
        "city"          => "Detroit",
        "id"            => "DET",
        "conference"    => "Western",
        "division"      => "Central"
    ),
    array(
        "name"          => "Oilers",
        "img"           => "oilers",
        "city"          => "Edmonton",
        "id"            => "EDM",
        "conference"    => "Western",
        "division"      => "Northwest"
    ),
    array(
        "name"          => "Panthers",
        "img"           => "panthers",
        "city"          => "Florida",
        "id"            => "FLA",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    ),
    array(
        "name"          => "Kings",
        "img"           => "kings",
        "city"          => "Los Angeles",
        "id"            => "LAK",
        "conference"    => "Western",
        "division"      => "Pacific"
    ),
    array(
        "name"          => "Wild",
        "img"           => "wild",
        "city"          => "Minnesota",
        "id"            => "MIN",
        "conference"    => "Western",
        "division"      => "Northwest"
    ),
    array(
        "name"          => "Canadiens",
        "img"           => "canadiens",
        "city"          => "Montreal",
        "id"            => "MTL",
        "conference"    => "Eastern",
        "division"      => "Northeast"
    ),
    array(
        "name"          => "Predators",
        "img"           => "predators",
        "city"          => "Nashville",
        "id"            => "NSH",
        "conference"    => "Western",
        "division"      => "Central"
    ),
    array(
        "name"          => "Devils",
        "img"           => "devils",
        "city"          => "New Jersey",
        "id"            => "NJD",
        "conference"    => "Eastern",
        "division"      => "Atlantic"
    ),
    array(
        "name"          => "Islanders",
        "img"           => "islanders",
        "city"          => "New York",
        "id"            => "NYI",
        "conference"    => "Eastern",
        "division"      => "Atlantic"
    ),
    array(
        "name"          => "Rangers",
        "img"           => "rangers",
        "city"          => "New York",
        "id"            => "NYR",
        "conference"    => "Eastern",
        "division"      => "Atlantic"
    ),
    array(
        "name"          => "Senators",
        "img"           => "senators",
        "city"          => "Ottawa",
        "id"            => "OTT",
        "conference"    => "Eastern",
        "division"      => "Northeast"
    ),
    array(
        "name"          => "Flyers",
        "img"           => "flyers",
        "city"          => "Philadelphia",
        "id"            => "PHI",
        "conference"    => "Eastern",
        "division"      => "Atlantic"
    ),
    array(
        "name"          => "Coyotes",
        "img"           => "coyotes",
        "city"          => "Phoenix",
        "id"            => "PHX",
        "conference"    => "Western",
        "division"      => "Pacific"
    ),
    array(
        "name"          => "Penguins",
        "img"           => "penguins",
        "city"          => "Pittsburgh",
        "id"            => "PIT",
        "conference"    => "Eastern",
        "division"      => "Atlantic"
    ),
    array(
        "name"          => "Sharks",
        "img"           => "sharks",
        "city"          => "San Jose",
        "id"            => "SJS",
        "conference"    => "Western",
        "division"      => "Pacific"
    ),
    array(
        "name"          => "Blues",
        "img"           => "blues",
        "city"          => "St. Louis",
        "id"            => "STL",
        "conference"    => "Western",
        "division"      => "Central"
    ),
    array(
        "name"          => "Lightning",
        "img"           => "lightning",
        "city"          => "Tampa Bay",
        "id"            => "TBL",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    ),
    array(
        "name"          => "Maple Leafs",
        "img"           => "mapleleafs",
        "city"          => "Toronto",
        "id"            => "TOR",
        "conference"    => "Eastern",
        "division"      => "Northeast"
    ),
    array(
        "name"          => "Canucks",
        "img"           => "canucks",
        "city"          => "Vancouver",
        "id"            => "VAN",
        "conference"    => "Western",
        "division"      => "Northwest"
    ),
    array(
        "name"          => "Capitals",
        "img"           => "capitals",
        "city"          => "Washington",
        "id"            => "WSH",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    ),
    array(
        "name"          => "Jets",
        "img"           => "jets",
        "city"          => "Winnipeg",
        "id"            => "WPG",
        "conference"    => "Eastern",
        "division"      => "Southeast"
    )
));        
.project-jquerytypeahead.page-demo .typeahead__result .name {
    margin: 0 10px;
}

.project-jquerytypeahead.page-demo .typeahead__result .division {
    font-size: 12px;
    color: #777;
    font-variant: small-caps;
}

.project-jquerytypeahead.page-demo .typeahead__result .team-logo {
    position: absolute;
    top: 0;
    right: 0;
    background-color: #fff;
    padding: 2px 4px 0 10px;
}

.project-jquerytypeahead.page-demo .typeahead__result .team-logo img {
    height: 26px;
}        
Font v1
  • Since there are many "various" themes and this keyword is not meaningful, source.theme.matcher is added to skip the search results
  • cache: true stores the lists inside localStorage so the data will be preserved even after changing page (less requests)
  • ttl sets the storage's "time to live" (in milliseconds) to 24 hours, default is 1 hour
  • compression: true uses LZString library to compress the large amount of data to be stored in localStorage.

    The jsonp call requested an array of objects containing 23811 fonts which weights 624k before compression and 86k after compression so ~14% of the original weight.

    Considering some browser have only 5mb of storage, this might be your best option



    $.typeahead({
        input: '.js-typeahead-font_v1',
        maxItem: 10,
        order: "asc",
        hint: true,
        group: true,
        dropdownFilter: "all",
        backdrop: {
            "opacity": 0.45,
            "filter": "alpha(opacity=45)",
            "background-color": "#fff"
        },
        cache: true,
        ttl: 86400000, // 1day
        compression: true,
        source: {
            font: {
                href: "http://www.enfont.com/{{display|slugify}}.font",
                ajax: {
                    url: "http://www.enfont.com/font/list.json/",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            theme: {
                matcher: function (item, value) {
                    // Skip items that has a matching value of "various"
                    return /various/.test(value) ? undefined : true;
                },
                href: "http://www.enfont.com/{{display|slugify}}.theme",
                ajax: {
                    url: "http://www.enfont.com/theme/list.json/",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            category: {
                href: "http://www.enfont.com/{{display|slugify}}.category",
                ajax: {
                    url: "http://www.enfont.com/category/list.json/",
                    dataType: "jsonp",
                    path: "data"
                }
            }
        },
        callback: {
            onClickAfter: function (node, a, item, event) {

                event.preventDefault();

                var r = confirm("You will be redirected to:\n" + item.href + "\n\nContinue?");
                if (r == true) {
                    window.open(item.href);
                }

                $('#result-container').text('');

            }
        },
        debug: true
    });

        

        

    
Game v1
  • Class .layout2 has been applied to override the default design, rules are inside jquery.typeahead.css
  • Fetching Typeahead search list from www.gamer-hub.com with jsonp cross domain request
  • Type "shoot" to see the result from multiple lists, "Sky Shooter" and "Elite shooter 6" are added inside the game list as extra search results
  • Inside the json response, data is an array of objects instead of a simple array. Any key can be retrieved in the callback function inside object parameter
  • dropdownFilter: "all" allows to filter the search result by list
  • onNavigateBefore is setting event.preventInputChange = true so the input text will not change when arrow UP or DOWN is pressed
  • onMouseEnter builds a popover thumbnail of the game
  • onClick opens a new window from a custom build url


    $.typeahead({
        input: '.js-typeahead-game_v1',
        minLength: 1,
        maxItem: 0,
        order: "asc",
        hint: true,
        group: true,
        maxItemPerGroup: 5,
        dropdownFilter: "all",
        source: {
            game: {
                data: [{
                    id: 777,
                    display: "Sky Shooter"
                }, {
                    id: 1001,
                    display: "Elite shooter 6"
                }],
                ajax: {
                    url: "http://www.gamer-hub.com/game/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            category: {
                ajax: {
                    url: "http://www.gamer-hub.com/category/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            tag: {
                ajax: {
                    url: "http://www.gamer-hub.com/tag/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            }
        },
        callback: {
            onNavigateBefore: function (node, query, event) {
                if (~[38,40].indexOf(event.keyCode)) {
                    event.preventInputChange = true;
                }
            },
            onClick: function (node, a, item, event) {
                window.open(
                    "http://www.gamer-hub.com/" +
                        item.group + "/" +
                        item.id + "/" +
                        item.display.replace(/[\s]|:\s/g, "-")
                            .replace("'", "-")
                            .toLowerCase()
                        + "/"
                );
            },
            onMouseEnter: function (node, a, item, event) {
                if (item.group !== "game") {
                    return false;
                }

                if (!$(a).find(".popover")[0]) {

                    $(a).append(
                        $("<div/>", {
                            "class": "popover fade right in",
                            "html": $("<div/>", {
                                "class": "popover-content",
                                "html": $("<img/>", {
                                    "src": "http://cdn.gamer-hub.com/images/" +
                                        item.display.replace(/[\s]|:\s/g, "-")
                                            .replace("'", "-")
                                            .replace(/-+/g, "-")
                                            .toLowerCase()
                                        + ".jpg"
                                })
                            }).prepend($("<div/>", {
                                "class": "arrow"
                            }))
                        })
                    );

                } else {
                    $(a).find(".popover").removeClass("out").addClass("in");
                }
            },
            onMouseLeave: function (node, a, item, event) {
                if (item.group !== "game") {
                    return false;
                }

                $(a).find(".popover").removeClass("in").addClass("out");
            }
        }
    });

        

        

    
/*------------------------------------*\
    BOOTSTRAP POPOVER
\*------------------------------------*/

.popover {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1010;
    display: none;
    max-width: 276px;
    padding: 1px;
    text-align: left;
    white-space: normal;
    background-color: #ffffff;
    border: 1px solid #ccc;
    border: 1px solid rgba(0, 0, 0, 0.2);
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    -webkit-box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    -webkit-background-clip: padding-box;
    -moz-background-clip: padding;
    background-clip: padding-box;
}

#form-game_v1 .popover {
    display: block;
    position: absolute;
    right: -135px;
    top: -30px;
    left: auto;
    width: 120px;
    height: 90px;
    -webkit-border-radius: 2px;
    -moz-border-radius: 2px;
    border-radius: 2px;
}

#form-game_v1 .popover.out {
    display: none;
}

#form-game_v1 .popover-content {
    padding: 0;
}

#form-game_v1 .popover-content img {
    width: 100%;
    height: 100%;
}

.popover.top {
    margin-top: -10px;
}

.popover.right {
    margin-left: 10px;
}

.popover.bottom {
    margin-top: 10px;
}

.popover.left {
    margin-left: -10px;
}

.popover-title {
    padding: 8px 14px;
    margin: 0;
    font-size: 14px;
    font-weight: normal;
    line-height: 18px;
    text-transform: capitalize;
    background-color: #f7f7f7;
    border-bottom: 1px solid #ebebeb;
    -webkit-border-radius: 5px 5px 0 0;
    -moz-border-radius: 5px 5px 0 0;
    border-radius: 5px 5px 0 0;
}

.popover-title:empty {
    display: none;
}

.popover-content {
    font-size: 13px;
    padding: 10px;
}

.popover-content > p {
    margin-top: 0;
}

.popover .arrow,
.popover .arrow:after {
    position: absolute;
    display: block;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
}

.popover .arrow {
    border-width: 11px;
}

.popover .arrow:after {
    border-width: 10px;
    content: "";
}

.popover.top .arrow {
    bottom: -11px;
    left: 50%;
    margin-left: -11px;
    border-top-color: #999;
    border-top-color: rgba(0, 0, 0, 0.25);
    border-bottom-width: 0;
}

.popover.top .arrow:after {
    bottom: 1px;
    margin-left: -10px;
    border-top-color: #ffffff;
    border-bottom-width: 0;
}

.popover.right .arrow {
    top: 50%;
    left: -11px;
    margin-top: -11px;
    border-right-color: #999;
    border-right-color: rgba(0, 0, 0, 0.25);
    border-left-width: 0;
}

.popover.right .arrow:after {
    bottom: -10px;
    left: 1px;
    border-right-color: #ffffff;
    border-left-width: 0;
}

.popover.bottom .arrow {
    top: -11px;
    left: 50%;
    margin-left: -11px;
    border-bottom-color: #999;
    border-bottom-color: rgba(0, 0, 0, 0.25);
    border-top-width: 0;
}

.popover.bottom .arrow:after {
    top: 1px;
    margin-left: -10px;
    border-bottom-color: #ffffff;
    border-top-width: 0;
}

.popover.left .arrow {
    top: 50%;
    right: -11px;
    margin-top: -11px;
    border-left-color: #999;
    border-left-color: rgba(0, 0, 0, 0.25);
    border-right-width: 0;
}

.popover.left .arrow:after {
    right: 1px;
    bottom: -10px;
    border-left-color: #ffffff;
    border-right-width: 0;
}        
Game v2
  • Click the input, type "zombie" and see what happens
  • There is no maxItem, instead every groups have a maxItemPerGroup: 16
  • backdropOnFocus will apply .backdrop class to .typeahead__container when the search input is focused. Some custom styles are set inside the CSS file to have a "Full-Page" search.
  • cache: sessionStorage will clear when the visitor close the browser
  • Custom source.game.template is calling the Typeahead helper.slugify function to generate a "clean" url
  • onShowLayout callback changes the input placeholder property and re-calculate .typeahead__list maximum height
  • onLayoutBuiltBefore clears the game group header


    window.onresize = function(event) {
        if ($('#form-game_v2').find('> .typeahead__container.backdrop')) {
            $('#form-game_v2').find('.typeahead__list').css('max-height', $(window).height() - 200 + "px")
        }
    }

    $.typeahead({
        input: '.js-typeahead-game_v2',
        minLength: 1,
        maxItem: false,
        highlight: false,
        hint: true,
        group: true,
        maxItemPerGroup: 16,
        backdrop: {
            "background-color": "#fff"
        },
        backdropOnFocus: true,
        cache: "sessionStorage",
        compression: true,
        cancelButton: false,
        template: function () {
          return '<span class="ui blue small label">{{display}}</span>';
        },
        source: {
            game: {
                href: "http://www.gamer-hub.com/game/{{id}}/{{display|slugify}}/",
                template: function (query, item) {
                    return '<img src="http://cdn.gamer-hub.com/images/' + this.helper.slugify.call(this, item.display) + '.jpg">' +
                        '<span class="title">{{display}}</span>';
                },
                ajax: {
                    url: "http://www.gamer-hub.com/game/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            tag: {
                href: "http://www.gamer-hub.com/tag/{{id}}/{{display|slugify}}/",
                ajax: {
                    url: "http://www.gamer-hub.com/tag/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            },
            category: {
                href: "http://www.gamer-hub.com/category/{{id}}/{{display|slugify}}/",
                ajax: {
                    url: "http://www.gamer-hub.com/category/list.json",
                    dataType: "jsonp",
                    path: "data"
                }
            }
        },
        callback: {
            onShowLayout: function (node, query) {
                node.attr('placeholder', 'Search for a Game ...');
                node.closest('form').find('.typeahead__list').css('max-height', $(window).height() - 200 + "px");
            },
            onHideLayout: function (node, query) {
                node.attr('placeholder', 'Search');
            },
            onLayoutBuiltBefore: function (node, query, result, resultHtmlList) {
                resultHtmlList.find('li[data-search-group="game"]').remove();
                return resultHtmlList;
            },
            onClickAfter: function (node, a, item, event) {

                event.preventDefault();

                var r = confirm("You will be redirected to:\n" + item.href + "\n\nContinue?");
                if (r == true) {
                    window.open(item.href);
                }

            }
        }
    })





        

        

    
#form-game_v2 .typeahead__container.backdrop {
    position: fixed !important;
    width: 80%;
    left: 10%;
    top: 50px;
}

#form-game_v2 .typeahead__container.backdrop .typeahead__query input {
    font-size: 3rem;
    height: auto;
    color: #333;
}

#form-game_v2 .typeahead__container.backdrop .typeahead__button {
    display: none;
}

#form-game_v2 li.typeahead__group {
    padding: 10px 10px 0;
}

#form-game_v2 li.typeahead__item {
    display: inline-block;
    font-size: 0;
    border: 0;
    position: relative;
    margin: 5px;
}

#form-game_v2 li.typeahead__item span.title {
    display: none;
    position: absolute;
    bottom: 0;
    width: 100%;
    text-transform: capitalize;
    border-radius: 0;
}

#form-game_v2 li.typeahead__item:hover span.title,
#form-game_v2 li.typeahead__item.active span.title {
    display: block;
}

#form-game_v2 li.typeahead__item span {
    font-size: 1rem;
    background: #fff;
    padding: 2px 5px;
    border-radius: 10px;
}

#form-game_v2 .typeahead__list {
    background: #fff;
    overflow-x: hidden;
    overflow-y: auto;
}

#form-game_v2 .typeahead__list a {
    padding: 1px;
}

#form-game_v2 .typeahead__list .typeahead__item a:hover {
    background: transparent;
}

#form-game_v2 .typeahead__list .typeahead__item a img {
    border: solid 1px transparent;
    width: 178px;
}

#form-game_v2 .typeahead__list .typeahead__item a:hover img,
#form-game_v2 .typeahead__list .typeahead__item.active a img {
    border-color: #4D90FE;
}

#form-game_v2 .typeahead__list .typeahead__item a:hover span {
    opacity: .8;
}

#form-game_v2 .typeahead__group a {
    background: transparent;
    font-size: 1.5rem;
    text-transform: uppercase;
    color: #ccc;
}

#form-game_v2 .ui.label {
    text-transform: capitalize;
}        

Guru demos

Game v3
  • Using minLength: 0 combined with generateOnLoad: true will trigger a search showing all results
  • maxItem: 0 means that the maxItem is disabled, all source data will be shown with no limit
  • Defining resultContainer: '#champion-list' means that the Typeahead results will be displayed inside the specified container
  • cache: true and ttl for one week, prevents re-doing calls to the API since we know the results are not going to change anytime soon
  • dynamicFilter is used on checkboxes, select and radio buttons. The checkboxes are defined with "OR" | and the other filters are "AND" & prefixes.
    See the dynamicFilter documentation to understand the selector and key properties.
  • emptyTemplate is using a function to display a different template based on the user query
  • Call to the League of Legend Dev API, please use your own api_key so this one doesn't get blocked
  • callback.done is used to add champion Classification and format the champion tags to be filterable
  • onResult callback displays the number of "matched" champions
  • onClickBefore prepare the modal window with the clicked champion details
  • onLayoutBuiltBefore creates champion popovers on hover with basic champion description
  • A custom function is binded on "clear filters" button to interact with advanced Typeahead functionalities (currently undocumented, you will have to investigate the code)
  • "Attack 10" checkbox allows the Champions to be filtered by their info.attack using the value attribute on the checkbox input
Launch Game_v3 Demo