ruben-ruvic/typeahead-bundle
A PHP bundle that brings typeahead autocomplete to your forms, wiring text inputs to live suggestion lookups so users get matches as they type. Configure sources, customize rendering, and drop it into existing forms with minimal setup.
First, calibrate the mismatch: ruben-ruvic/typeahead-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config/typeahead.php, and no facade. As a Laravel developer you have three realistic entry points:
If you're in a pure Laravel app, do not install this — you'll get an autoloadable bundle class that nothing in Laravel knows how to boot. Build the equivalent with a Blade partial + a JSON route (~30 lines) instead.
If you are in a Symfony app, the minimal path:
composer require ruben-ruvic/typeahead-bundle
Register it — Symfony Flex (config/bundles.php):
return [
// ...
RubenRuvic\TypeaheadBundle\TypeaheadBundle::class => ['all' => true],
];
…or legacy AppKernel.php: new RubenRuvic\TypeaheadBundle\TypeaheadBundle().
Where to look first: open vendor/ruben-ruvic/typeahead-bundle/ and read two things before the README — the Form/Type/ directory (the actual FQCN of the type you'll reference) and Resources/views/ (the Twig block that renders the markup). With 0 stars and a 2022 last release, the README may lag the code; the source is the contract.
First use case — replace a free-text "search user" field with a remote autocomplete:
use RubenRuvic\TypeaheadBundle\Form\Type\TypeaheadType; // confirm FQCN in vendor/
$builder->add('user', TypeaheadType::class, [
'source' => $this->router->generate('api_user_search'),
]);
Then wire the JSON endpoint the field calls. Keep the payload to [{id, value}] — most Typeahead builds expect value for display.
Remote source + controller endpoint. The bundle gives you the form type; you still own the JSON contract. The standard loop:
// SearchController::users()
$q = $request->query->get('q', '');
$rows = $repo->createQueryBuilder('u')
->where('u.name LIKE :q')
->setParameter('q', $q.'%')
->setMaxResults(10)
->getQuery()
->getArrayResult();
return $this->json(array_map(fn($u) => ['id' => $u['id'], 'value' => $u['name']], $rows));
Prefetch vs. remote. Small, bounded lists (< ~500 rows) should be prefetch-ed as a static array so you skip the round-trip and the endpoint entirely. Switch to remote only when the dataset is unbounded or permission-scoped.
Entity-backed fields. If the submitted value must resolve to an entity, wrap the type with a DataTransformer (id ⇄ entity) or a query_builder option on any related EntityType. The typeahead widget is a presentation layer — don't let it become the validation layer.
Asset integration. Publish the bundle assets once (bin/console assets:install --symlink), then either include them in your base layout or, better, pull typeahead.js + jQuery through Webpack Encore and use the bundle only for the form rendering.
The Laravel translation of the same pattern, which is what you'll actually ship in a Laravel codebase:
// routes/web.php
Route::get('/users/search', [UserSearchController::class, 'index'])->name('users.search');
// Blade
<x-typeahead name="user_id" :source="route('users.search')" />
The Blade component owns the <input>, the data-source attribute, and the small typeahead.js init. Same architecture, no Symfony kernel.
Reuse. Extend the type rather than re-specifying options at every call site — a UserTypeaheadType with your route name and display key baked in keeps 15 forms consistent.
extra.laravel.providers, no auto-discovery. Installing it just to "try it" is a dead end; vendor the JS and copy the pattern.composer.json, and expect to fork it the moment a Symfony major bump breaks the FormType signature. Budget a half-day for that.typeahead.js separately. Loading both copies produces duplicated dropdowns and confusing "two menus" bugs that look like a bundle fault but aren't.ProvidePlugin ($/jQuery) or an explicit ordered entry — not a <script> tag jammed into the template.label vs value) are the #1 cause. Then check the query for a leading-wildcard LIKE '%…' that's silently full-scanning.LIMIT 10 and an index you'll DOS your own DB during a demo.POST, remember the token; if it leaks PII (emails, phone numbers), scope the query by the current user — autocomplete endpoints are a classic enumeration hole.form_themes in config/packages/twig.yaml rather than editing vendor files; customize the block prefix with getBlockPrefix() if you need a distinct template; a DataTransformer is the clean seam for entity resolution.config/packages/typeahead.yaml — if it exists, it'll be under Resources/config/ and it will be minimal.config/bundles.php? (2) does bin/console debug:form list the type? (3) do the JS assets load (Network tab, 200s)? (4) does the endpoint return the right shape? That sequence resolves ~95% of failures with this kind of bundle.How can I help you explore Laravel packages today?