Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Typeahead.js Laravel Package

twitter/typeahead.js

Typeahead.js is Twitter's fast, flexible autocomplete library, pairing the Bloodhound suggestion engine with a jQuery plugin for local and remote datasets. It offers customizable templates, smart filtering, and easy integration for search-as-you-type inputs.

Deep Wiki
Context7

Getting Started

Typeahead.js ships two layers that you will almost always use together:

  1. Bloodhound – the suggestion engine (local arrays, prefetch, remote AJAX, caching, ranking).
  2. Typeahead – the UI layer (input rendering, keyboard nav, templates, events).

Minimal wiring:

<link rel="stylesheet" href="typeahead.css">
<script src="jquery.js"></script>
<script src="typeahead.bundle.js"></script>
var states = new Bloodhound({
  datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  local: [{ name: 'Alabama' }, { name: 'Alaska' }]
});

$('.typeahead').typeahead(null, {
  name: 'states',
  displayKey: 'name',
  source: states
});

Where to look first:

  • typeahead.bundle.js (or typeahead.bundle.min.js) – one file gives you both Bloodhound and Typeahead. Prefer the bundle unless you have a reason to split.
  • The example/README Templates and Events sections – these describe ~90% of the customization you will actually do.
  • Your own displayKey – the single most important config after source. Get this right and the rest falls into place.

First use case that almost every project hits: a search box with a remote JSON endpoint. That means a Bloodhound instance with remote: { url, wildcard, transform }, a typeahead call pointed at it, and minLength to keep the request count sane.

Watch the version: 0.11.x is the current API (displayKey, synchronous source functions, async option on Bloodhound datasets). If you copy 0.10-era snippets you will get display vs displayKey bugs. Check the version in the file header before trusting any tutorial.

Implementation Patterns

Local / prefetch / remote, chosen per dataset

Bloodhound lets a single typeahead consume multiple sources. Use it:

var people = new Bloodhound({
  datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  prefetch: { url: '/api/people.json', cache: true },
  remote:   { url: '/api/people?q=%QUERY', wildcard: '%QUERY' }
});

$('#search').typeahead(
  { hint: false, highlight: true, minLength: 2 },
  { name: 'people', displayKey: 'name', source: people, limit: 8 },
  { name: 'projects', displayKey: 'title', source: projectEngine }
);

Pattern: prefetch for stable reference data, remote for user-typed queries, local for tiny static lists. Prefetch + cache: true removes a whole class of redundant network traffic.

Templates for real results

Default templates are text-only. Almost every real UI needs richer rows:

templates: {
  suggestion: function (d) {
    return '<div class="tt-row"><img src="' + d.avatar + '"><strong>' + d.name + '</strong><br>' + d.email + '</div>';
  },
  notFound: '<div class="tt-empty">No matches</div>',
  footer: '<div class="tt-footer">Press Enter to search</div>'
}

Use empty and pending templates too; they are the difference between "broken" and "loading".

Event-driven workflows

Typeahead emits jQuery events on the input. The useful ones:

  • typeahead:select – user picked a suggestion. Fire your "navigate" or "apply filter" logic here.
  • typeahead:autocomplete – user accepted the inline hint (Tab / Right Arrow). Often you want the same handler as select.
  • typeahead:asyncrequest / asyncreceive / asyncsuccess / asyncerror – wrap in a loading spinner.
  • typeahead:open / typeahead:close – toggle surrounding UI.
$('#search').on('typeahead:select typeahead:autocomplete', function (e, datum) {
  window.location.href = '/person/' + datum.id;
});

Bloodhound as the integration seam

Because Bloodhound is just a suggestion engine, you can use it without the UI:

  • engine.get(query, cb) for programmatic lookups (e.g., a custom dropdown).
  • engine.initialize() to warm the prefetch cache during idle time.
  • engine.add([...]) to inject entries after a successful create/save.
  • engine.clear() when the underlying data changes and you don't want stale caches.

This is often the most useful pattern in day-to-day work: treat Bloodhound as a small cache-and-rank library, and drive your own markup from get().

Bootstrap / CSS-framework integration

The generated markup is wrapped in .twitter-typeahead > .tt-hint + .tt-input + .tt-menu. With Bootstrap, drop .tt-* into your input group and restyle .tt-menu to match .dropdown-menu. Set position: relative on the wrapper and make sure nothing in your framework sets input { width: 100% } differently on .tt-input vs .tt-hint – misalignment here is the classic visual bug.

Progressive enhancement / no-results path

  • Set minLength so empty focus doesn't fire requests.
  • Provide notFound text and a typeahead:asyncerror handler that falls back to a plain submit.
  • Ensure the form still works if JS fails – typeahead is additive, not required.

Gotchas and Tips

display vs displayKey

0.10 uses display; 0.11 uses displayKey. If results appear in the menu but the input stays blank after selecting one, you are on 0.11 with display. This is the #1 reported issue on every tutorial that copied 0.10.

Tokenizers are mandatory and easy to get wrong

datumTokenizer and queryTokenizer are required on Bloodhound. For object arrays you need Bloodhound.tokenizers.obj.whitespace('field'), not flat whitespace. Wrong tokenizer = no matches, but no error, which makes it feel like the data isn't loading. Log engine.get('some query', console.log) to confirm.

Remote requests fire a lot

Without minLength and limit, every keystroke triggers an AJAX call and renders everything returned. Also use rateLimitWait / rateLimitBy on Bloodhound (wait ms) to debounce. If your backend isn't idempotent/fast, you'll see out-of-order results – Bloodhound cancels in-flight requests, but a slow server can still surface stale suggestions if sufficient isn't set.

sufficient – for remote datasets returning partial results, add sufficient: function (q, result) { return result.length >= 5; } so Bloodhound stops asking for more data once it has enough. Forgetting this causes "it keeps hitting my API even when results are shown."

jQuery dependency

Typeahead.js requires jQuery. If you're building a modern JIT/Vite/Turbo app, this is the main adoption cost – load jQuery globally or use one of the community forks (e.g., corejs-typeahead), which is the practical path when the original repo is archived.

The project is archived

twitter/typeahead.js is no longer maintained upstream (last release 0.11.1). Check actively maintained forks/alternatives before betting a new project on it. If you inherit it, treat the bundled .js as pinned and avoid patching.

.tt-hint misalignment

The hint input is an overlay. Any padding, font-size, or border difference between .tt-input and .tt-hint shifts the ghost text. Fix by making both inherit a shared class rather than duplicating styles.

typeahead:select vs native input events

When a suggestion is chosen, the input's change event fires after typeahead's select, and the value may be the display string, not your id. Keep the selected datum in a hidden input inside your select handler – don't try to reverse-map the display string later.

identify and merging results

identify defaults to the display string. When you merge datasets or update via engine.add(), provide identify: function (d) { return d.id; } so duplicates are deduped correctly. Without it, the same object from prefetch and remote shows twice.

Debugging checklist

  • Menu never opens? Check source returns a function/engine, minLength satisfied, and displayKey matches a real field.
  • Menu opens empty? Template returns nothing or HTML string with errors – check templates.suggestion.
  • Nothing highlights? highlight: true must be on the first argument (the options object), not the dataset.
  • Prefetch works in dev but not prod? CORS on the static JSON, or a cached copy at localStorage from a previous schema version – engine.clear() / bump the cache key.
  • Async data "sticks" after delete? Call engine.clear() and re-initialize(); Bloodhound caches per query.

Extension points worth knowing

  • Custom sorter for non-default ranking.
  • Custom matcher when you need fuzzy matching beyond tokenizers.
  • Multiple datasets to combine several engines under one input (typeahead(null, dsA, dsB)).
  • source as a plain function (query, syncResults) => ... for one-off lists where Bloodhound is overkill.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections