tnt-freskim-veliu/livewire-spotlight-search
Install Dependencies Ensure your project has:
composer require livewire/livewire tnt-freskim-veliu/livewire-spotlight-search
npm install alpinejs tailwindcss
Verify Tailwind is configured in resources/css/app.css and Alpine is included in your layout.
Publish Config Run:
php artisan vendor:publish --tag=livewire-spotlight-search-config
Update config/livewire-spotlight-search.php with your Searchable class (e.g., App\SpotlightSearch\UserSearch).
Add Script Directive
Include this in your Blade layout (e.g., resources/views/layouts/app.blade.php):
@livewireSpotlightSearchScript
Render the Component Place the component in your Blade view:
<livewire:spotlight-search />
Create a Searchable Class
Implement the Searchable contract in a class (e.g., app/SpotlightSearch/UserSearch.php):
use TNTFreskimVeliu\LivewireSpotlightSearch\Contracts\Searchable;
class UserSearch implements Searchable {
public function search(string $query): array { ... }
public function group(): string { return "Users"; }
}
Test the Search Refresh the page and type in the spotlight input to see results.
Define Searchable Models
Create a Searchable class for each model/type you want to search (e.g., UserSearch, ProductSearch).
Example:
class ProductSearch implements Searchable {
public function search(string $query): array {
return Product::query()
->where('name', 'like', "%$query%")
->orWhere('sku', 'like', "%$query%")
->take(10)
->get()
->toArray();
}
public function group(): string { return "Products"; }
}
Configure Multiple Searchables Update the config to support multiple search types:
return [
'searchable' => [
'users' => App\SpotlightSearch\UserSearch::class,
'products' => App\SpotlightSearch\ProductSearch::class,
],
];
Customize UI Override the default Tailwind styles by publishing views:
php artisan vendor:publish --tag=livewire-spotlight-search-views
Modify resources/views/vendor/livewire-spotlight-search/spotlight-search.blade.php.
Dynamic Query Building Use Laravel Query Builder features for complex searches:
public function search(string $query): array {
return User::query()
->when($query, fn($q) => $q->where(function($query) use ($query) {
$query->where('name', 'like', "%$query%")
->orWhere('email', 'like', "%$query%");
}))
->take(20)
->get()
->toArray();
}
Integration with Livewire Properties Extend the component by creating a custom Livewire class:
class CustomSpotlightSearch extends \TNTFreskimVeliu\LivewireSpotlightSearch\SpotlightSearch {
public function mount() {
$this->searchable = new App\SpotlightSearch\UserSearch();
}
}
Use it in Blade:
<livewire:custom-spotlight-search />
Alpine.js Extensions Enhance reactivity with Alpine.js (e.g., auto-focus, debounce):
<input
x-data="{ debounce: null }"
x-on:input.debounce="debounce = setTimeout(() => $wire.search($event.target.value), 300)"
x-on:blur="clearTimeout(debounce)"
wire:model="query"
>
Missing Dependencies
@alpinejs and Tailwind are loaded in your layout. Add to resources/js/app.js:
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
Searchable Contract Not Implemented
Searchable or missing required methods (search, group).TNTFreskimVeliu\LivewireSpotlightSearch\Contracts\Searchable and includes both methods.Case Sensitivity in LIKE Queries
LIKE queries may be case-sensitive depending on the database collation.LOWER() or ILIKE (PostgreSQL) for case-insensitive searches:
->where('name', 'LIKE', "%{$query}%")
or
->whereRaw('LOWER(name) LIKE LOWER(?)', ["%{$query}%"])
Performance with Large Datasets
take() (default is 25).tsvector, MySQL MATCH AGAINST).Caching Search Results
search method:
public function search(string $query): array {
return Cache::remember("spotlight_{$query}", now()->addMinutes(5), function() use ($query) {
return User::query()->where('name', 'like', "%$query%")->take(25)->get()->toArray();
});
}
Tailwind CSS Conflicts
!important sparingly:
<div class="spotlight-result !bg-blue-100">...</div>
Alpine.js XSRF Protection
@csrf is in your layout and use wire:key for dynamic components:
<div wire:key="search-{{ $query }}">...</div>
Log Search Queries
Add logging to the search method to debug queries:
public function search(string $query): array {
\Log::debug("Search query: {$query}");
return User::query()->where('name', 'like', "%$query%")->get()->toArray();
}
Check Livewire Wire:ignore
If the component isn’t updating, ensure dynamic elements aren’t wrapped in wire:ignore:
<!-- Bad: Blocks reactivity -->
<div wire:ignore>
<input x-model="query">
</div>
<!-- Good: Allows Alpine + Livewire -->
<div>
<input x-model="query" wire:model="query">
</div>
Verify Published Config
After publishing, check config/livewire-spotlight-search.php for typos or incorrect class names.
Clear Blade Cache If changes aren’t reflecting, clear the cache:
php artisan view:clear
php artisan cache:clear
Custom Result Rendering
Override the result template in resources/views/vendor/livewire-spotlight-search/spotlight-search.blade.php:
@foreach($results as $result)
<div class="p-2 border-b">
<h3 class="font-bold">{{ $result['name'] }}</h3>
<p class="text-sm text-gray-500">{{ $result['email'] }}</p>
</div>
@endforeach
Add Search Filters Extend the component to support filters (e.g., search by role):
public function search(string $query, ?string $role = null): array {
$query = User::query()->where('name', 'like', "%$query%");
if ($role) $query->where('role', $role);
return $query->take(25)->get()->toArray();
}
Pass filters via Livewire properties or URL parameters.
Integration with Laravel Scout
For advanced search, replace the search method with Scout:
public function search(string $query): array {
return User::
How can I help you explore Laravel packages today?