Autocomplete Search Component using Livewire
Tailwind CSS New Livewire
Demo
This is a pro component. Get Livewiredemos pro access to view / download the component code.
Component Class
<?php
namespace App\Http\Livewire;
use App\Models\DummyProduct;
use Livewire\Component;
use Illuminate\Http\Request;
use Spatie\Searchable\Search;
class SearchComponent extends Component
{
public $keyword;
public $searchResults;
public $resultCountToShow = 5;
public function render()
{
return view('livewire.search-component');
}
public function updatedKeyword($keyword){
$this->searchResults = (new Search())
->registerModel(DummyProduct::class, ['title', 'description'])
->search($keyword);
}
}
Component View File
<div class="flex justify-center flex-1 lg:mr-32">
<div
class="relative w-full max-w-xl mr-6 focus-within:text-purple-500"
>
<div class="absolute inset-y-0 flex items-center pl-2">
<svg
class="w-4 h-4"
aria-hidden="true"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
clip-rule="evenodd"
></path>
</svg>
</div>
<input
class="w-full leading-10 pl-8 pr-2 text-sm text-gray-700 placeholder-gray-600 bg-gray-100 border-0 rounded-md dark:placeholder-gray-500 dark:focus:shadow-outline-gray dark:focus:placeholder-gray-600 dark:bg-gray-700 dark:text-gray-200 focus:placeholder-gray-500 focus:bg-white focus:border-purple-300 focus:outline-none focus:shadow-outline-purple form-input"
type="text"
placeholder="Search for products"
aria-label="Search"
wire:model.debounce.300ms="keyword"
wire:keydown.enter="searchResults"
/>
<button wire:click="searchResults" class="absolute inset-y-0 right-0 px-4 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-r-md active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">
<i class="fas fa-search"></i>
</button>
<!-- Search Results -->
<div class="relative" >
<div wire:loading.delay class="absolute top-100 mt-1 w-full border bg-white shadow-xl rounded text-center"><img src="/images/loading-buffering.gif" class="w-10 h-10 my-1 mx-auto"/></div>
@if(isset($searchResults) && !empty($keyword))
<div class="absolute top-100 mt-1 w-full border bg-white shadow-xl rounded">
<div class="p-3">
@if($searchResults->count() > 0)
<div class="divide-y" x-ref="list">
@foreach($searchResults as $key => $searchResult)
@if ($key == $resultCountToShow)
@break
@endif
<a href="{{$searchResult->url}}" class="p-2 flex block w-full rounded hover:bg-gray-100">
<img class="rounded-full border-1 border-gray-300 w-8 h-8 p-1" src="{{$searchResult->searchable->getFirstMediaUrl('images')}}" />
<span>{{$searchResult->title}}</span>
</a>
@endforeach
</div>
@elseif($searchResults->count() == 0)
<a href="#" class="p-2 flex block w-full rounded text-gray-700">
<span>No Results Found</span>
</a>
@endif
</div>
</div>
@endif
</div>
</div>
</div>
Usage
To include the search box on your page or navigation you just have to include the livewire component.
@livewire('search-component')
Documentation
In this demonstration we are using spatie searchable package for our search operation.
You must install it first.
composer require spatie/laravel-searchable
Preparing your Model
In this demonstration, I performed a search on a Model named DummyProduct. In order to search through models you'll have to let them implement the Searchable interface.
You'll only need to add a getSearchResult
method to each searchable model that must return an instance of SearchResult. Here's how it could look like for a DummyProduct model.
class DummyProduct extends Model implements Searchable
{
...
..
public function getSearchResult(): SearchResult
{
return new SearchResult(
$this,
$this->title,
$this->link
);
}
}
Livewire Component code is simple, we have utilized the updated hook on the keyword variable. Thus whenever user type in the keyword, livewire components runs a query on the database to gather the results. We then run through the results on the frontend.