In this section, let's dive into more complex and practical stuff: we will create a CRUD with Livewire. Let's start by creating a table in Laravel, moving it to Livewire, and adding pagination to the table.
Initial Structure
For the initial Laravel project, we will have a Product Model and a page to list all the products.
database/migrations/xxxx_create_products_table.php:
Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('description'); $table->timestamps();});
app/Models/Product.php:
use Illuminate\Database\Eloquent\Factories\HasFactory; class Product extends Model{ use HasFactory; protected $fillable = [ 'name', 'description', ];}
database/factories/ProductFactory.php:
class ProductFactory extends Factory{ public function definition(): array { return [ 'name' => $this->faker->name(), 'description' => $this->faker->text(50), ]; }}
database/seeders/DatabaseSeeder.php:
class DatabaseSeeder extends Seeder{ public function run(): void { Product::factory(50)->create(); }}
Don't forget to run Seeder when migrating database
php artisan migrate --seed.
app/Http/Controllers/ProductController.php:
use App\Models\Product;use Illuminate\Contracts\View\View; class ProductController extends Controller{ public function index(): View { $products = Product::all(); return view('products.index', compact('products')); }}
routes/web.php:
Route::get('products', [\App\Http\Controllers\ProductController::class, 'index']);
resources/views/products/index.blade.php:
<x-app-layout> // ... layout header code <div class="min-w-full align-middle"> <table class="min-w-full divide-y divide-gray-200 border"> <thead> <tr> <th class="px-6 py-3 bg-gray-50 text-left"> <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Name</span> </th> <th class="px-6 py-3 bg-gray-50 text-left"> <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Description</span> </th> <th class="px-6 py-3 bg-gray-50 text-left"> </th> </tr> </thead> <tbody class="bg-white divide-y divide-gray-200 divide-solid"> @forelse($products as $product) <tr class="bg-white"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900"> {{ $product->name }} </td> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900"> {{ $product->description }} </td> <td> <a href="#" class="inline-flex items-center px-4 py-2 bg-gray-800 rounded-md font-semibold text-xs text-white uppercase tracking-widest"> Edit </a> <a href="#" class="inline-flex items-center px-4 py-2 bg-red-600 rounded-md font-semibold text-xs text-white uppercase tracking-widest"> Delete </a> </td> </tr> @empty <tr> <td class="px-6 py-4 text-sm" colspan="3"> No products were found. </td> </tr> @endforelse </tbody> </table></div> // ... layout footer code </x-app-layout>
Notice: In this tutorial, we use the Laravel Breeze layout with x-app-layout Blade component, but feel free to use any other layout. Read more in the docs.
After visiting the /products page, you should see a table with the list of products.

Move to Livewire Component
Now let's move the table to the Livewire component. First, we need a component.
php artisan make:livewire Products
Next, the whole table code move into the Livewire components...
Hi I got an error when I use the pagination, I follow all the steps. but still got an error. Method Illuminate\Database\Eloquent\Collection::links does not exist.
Does anyone encounter the same issue with mine?
that has happened to me when the paginate method isn't being used, check that you did replace this in the render method on the component : 'products' => Product::all().
with 'products' => Product::paginate(10),
I did that too. I don't know why I'm having this kind of issue.
Base on the example, it doesn't have the mount() method, if I don't put the mount() method in my component then there's another an issue which is Illuminate\Database\Eloquent\Collection::links does not exist.. I'm confused. I hope somebody can help me on this.