$ laravel new livewire-search && cd livewire-search $ composer require livewire/livewire npx. Alternatively, you can link to Tailwind CSS directly from the CDN. For production usage, the documentation recommends that you set it up as a PostCSS plugin. Generate the Tailwind CSS files by running:$ npx tailwindcss-cli@latest build -o public/css/tailwind.css tailwind.css file in the public/css folder. We can then import it to our Blade templates using HTML <link> tags as we would any other stylesheet.bio field and a FULLTEXT index.database/migrations/2014_10_12_000000_create_users_table.php) and replace its content with the following:<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->mediumText('bio'); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); DB::statement( 'ALTER TABLE users ADD FULLTEXT fulltext_index(name, email, bio)' ); } public function down() { Schema::dropIfExists('users'); } } database/factories/UserFactory.php (feel free to create it if it doesn’t exist) and replace the definition method with the code block below:<?php public function definition() { return [ 'name' => $this->faker->name, 'email' => $this->faker->unique()->safeEmail, 'bio' => $this->faker->text(200), 'email_verified_at' => now(), 'password' => Hash::make("password"), 'remember_token' => Str::random(10), ]; } run method of the database seeder class (/database/seeders/DatabaseSeeder.php) to the one below.public function run() { \App\Models\User::factory(50)->create(); } users table when the seeder is run. Apply the migrations and the seeders by running the set of commands below.$ php artisan migrate && php artisan db:seed Search trait that we can use from any Laravel model by adding a $searchable field to the model. This should represent the fields that have been added to a FULLTEXT index. Then, create a new file, named Search.php, file in app/Models, and add the trait implementation shown below:<?php namespace App\Models; trait Search { private function buildWildCards($term) { if ($term == "") { return $term; } // Strip MySQL reserved symbols $reservedSymbols = ['-', '+', '<', '>', '@', '(', ')', '~']; $term = str_replace($reservedSymbols, '', $term); $words = explode(' ', $term); foreach($words as $idx => $word) { // Add operators so we can leverage the boolean mode of // fulltext indices. $words[$idx] = "+" . $word . "*"; } $term = implode(' ', $words); return $term; } protected function scopeSearch($query, $term) { $columns = implode(',', $this->searchable); // Boolean mode allows us to match john* for words starting with john // (https://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html) $query->whereRaw( "MATCH ({$columns}) AGAINST (? IN BOOLEAN MODE)", $this->buildWildCards($term) ); return $query; } } buildWildCards and scopeSearch. buildWildCards cleans up the search term by:+ and *) to the search term. This helps it to take advantage of MySQL’s boolean mode.scopeSearch on the other hand is a Laravel local scope (identified by the “scope” prefix). Models are automatically searchable via a static search method once they:Search trait.$searchable array that contains the columns that should be searched e.g the User model below searches the name, email, and bio columns.Search trait into the User model class, and set up the $searchable fields as shown below:<?php namespace App\Models; /* --- existing code here --- */ class User extends Authenticatable { use HasFactory, Notifiable; use Search; // Use the search trait we created earlier /* --- existing code here --- */ protected $searchable = [ 'name', 'email', 'bio', ]; /* -- rest of user class code --- */ } @livewireStyles and @livewireScripts directive within the <head> tag, and at the end of the <body> tag respectively, in your app layout. So, in resources/views/welcome.blade.php add the code below:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@yield('title', 'My cool Livewire App')</title> @livewireStyles </head> <body> <!-- other app content goes here--> @livewireScripts </body> </html> @livewire directive or the livewire tag, e.g:<div> @livewire('search-users') </div> <!-- This also works --> <div> <livewire:search-users /> </div> app/Http/Livewire and are automatically generated when you generate a component with php artisan make:livewire.wire: attribute. For instance, The snippet below binds the value of the text field to a $name variable in the component class, and the value of $name is rendered within the h1 tag as it changes. <input wire:model="message" type="text"> <h1>{{ $message }}</h1> SearchUser component by running the artisan command below, in the project folder.$ php artisan make:livewire SearchUser app/Http/Livewire/SearchUser.php: The component class that interacts with our database and prepares the data to be rendered.resources/views/livewire/search-user.blade.php: The component template that holds the UI for the component.app/Http/Livewire/SearchUser.php) and add the code below to it:<?php namespace App\Http\Livewire; use App\Models\User; use Livewire\Component; class SearchUser extends Component { public $term = ""; public function render() { sleep(1); $users = User::search($this->term)->paginate(10); $data = [ 'users' => $users, ]; return view('livewire.search-user', $data); } } search method on the User model class (which User inherited from the Search trait) and paginates the result. The result is then returned with the component template in the same way we would do it from a regular Laravel controller.sleep call to the code above. This is to delay the code execution to simulate a page load. This delay will help us see Livewire’s loading state in action in our development environment.resources/views/livewire/search-user.blade.php) and add the code block below to it:<div> <div class="px-4 space-y-4 mt-8"> <form method="get"> <input class="border-solid border border-gray-300 p-2 w-full md:w-1/4" type="text" placeholder="Search Users" wire:model="term"/> </form> <div wire:loading>Searching users...</div> <div wire:loading.remove> <!-- notice that $term is available as a public variable, even though it's not part of the data array --> @if ($term == "") <div class="text-gray-500 text-sm"> Enter a term to search for users. </div> @else @if($users->isEmpty()) <div class="text-gray-500 text-sm"> No matching result was found. </div> @else @foreach($users as $user) <div> <h3 class="text-lg text-gray-900 text-bold">{{$user->name}}</h3> <p class="text-gray-500 text-sm">{{$user->email}}</p> <p class="text-gray-500">{{$user->bio}}</p> </div> @endforeach @endif @endif </div> </div> <div class="px-4 mt-4"> {{$users->links()}} </div> </div> $term variable in the component class to the search field. We’ve also used wire:loading to show the div when our data is loading. Finally, we used wire:loading.remove to hide the div containing the search results when loading.welcome.blade.php file that was automatically generated by Laravel, and rendering the component within the welcome template. While we’re at it, we will also include the Tailwind CSS file we generated while setting up the application.welcome.blade.php file and replace its content with the code below:<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>uSearch</title> <link href="/css/tailwind.css" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet"> <style> body { font-family: 'Nunito'; } </style> @livewireStyles </head> <body> <header class="bg-gray-900 text-gray-200 w-full py-4 px-4"> uSearch </header> <livewire:search-user/> @livewireScripts </body> </html> php artisan serve in a terminal and the command should launch the server on http://localhost:8000. Visit the application URL (http://localhost:8000) in your browser to see the home page below: