Skip to main content

Introduction

This guide will walk you through creating a fully functional data table with search, sorting, filtering, pagination, and bulk actions. By the end, you’ll have a production-ready table component.
This tutorial assumes you have already installed Laravel Livewire Tables.

Creating Your First Table

1

Install the Package

If you haven’t already, install the package via Composer:
composer require alp-develop/laravel-livewire-tables
For Tailwind CSS users, add this CSS rule to prevent Alpine.js flicker:
[x-cloak] { display: none !important; }
2

Generate a Table Component

Use the Artisan command to generate a new table component. The command accepts two arguments: the table name and the model name.
php artisan make:livewiretable UsersTable User
This creates a file at app/Livewire/Tables/UsersTable.php with auto-detected columns from your database schema.
The generator automatically introspects your database table and creates columns based on the schema. It skips sensitive fields like password and remember_token.
Generate in a subdirectory:
php artisan make:livewiretable Admin/UsersTable User
3

Review the Generated Code

Here’s what the generator creates for a User model:
<?php

namespace App\Livewire\Tables;

use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Tables\Columns\BooleanColumn;
use Livewire\Tables\Columns\TextColumn;
use Livewire\Tables\Filters\BooleanFilter;
use Livewire\Tables\Livewire\DataTableComponent;

class UsersTable extends DataTableComponent
{
    public function configure(): void
    {
        $this->setDefaultPerPage(10);
    }

    public function query(): Builder
    {
        return User::query();
    }

    public function columns(): array
    {
        return [
            TextColumn::make('name')
                ->label('Name')
                ->sortable()
                ->searchable(),

            TextColumn::make('email')
                ->label('Email')
                ->sortable()
                ->searchable(),
        ];
    }

    public function filters(): array
    {
        return [
            // Add filters here
        ];
    }
}
The query() method returns an Eloquent Builder, so you can add eager loading, scopes, or joins as needed.
4

Use the Table in a Blade View

Render the table component in any Blade template:
<livewire:tables.users-table />
Or with a fully qualified name:
@livewire('tables.users-table')
5

See the Result

Visit the page in your browser. You’ll see a fully functional data table with:
  • ✅ Global search across searchable columns
  • ✅ Column sorting (click headers)
  • ✅ Pagination with per-page dropdown
  • ✅ Responsive design
  • ✅ Empty state message

Complete Example with All Features

Here’s a production-ready example that demonstrates all major features:
<?php

namespace App\Livewire\Tables;

use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Tables\Columns\TextColumn;
use Livewire\Tables\Columns\BooleanColumn;
use Livewire\Tables\Columns\ActionColumn;
use Livewire\Tables\Filters\SelectFilter;
use Livewire\Tables\Livewire\DataTableComponent;

class UsersTable extends DataTableComponent
{
    public function configure(): void
    {
        $this->setDefaultPerPage(25);
        $this->setSearchDebounce(300);
        $this->setDefaultSortDirection('desc');
        $this->setEmptyMessage('No users found.');
    }

    public function query(): Builder
    {
        return User::query();
    }

    public function columns(): array
    {
        return [
            TextColumn::make('name')->sortable()->searchable(),
            TextColumn::make('email')->sortable()->searchable(),
            BooleanColumn::make('active')->sortable(),
            TextColumn::make('created_at')
                ->label('Joined')
                ->sortable()
                ->format(fn($value) => $value?->format('M d, Y')),
            ActionColumn::make()
                ->button('Edit', fn($row) => "edit({$row->id})", 'lt-btn-primary')
                ->button('Delete', fn($row) => "delete({$row->id})", 'lt-btn-primary'),
        ];
    }

    public function filters(): array
    {
        return [
            SelectFilter::make('active')
                ->label('Status')
                ->setOptions(['' => 'All', '1' => 'Active', '0' => 'Inactive'])
                ->filter(fn(Builder $q, $v) => $q->where('active', (bool) $v)),
        ];
    }

    public function bulkActions(): array
    {
        return [
            'deleteSelected' => 'Delete Selected',
            'exportCsvAuto'  => 'Export CSV',
        ];
    }

    public function deleteSelected(): void
    {
        User::whereIn('id', $this->getSelectedIds())->delete();
    }

    public function edit(int $id): void
    {
        $this->redirect(route('users.edit', $id));
    }

    public function delete(int $id): void
    {
        User::findOrFail($id)->delete();
    }
}

What This Example Includes

Search & Sort

Global search across name and email with 300ms debounce. Click any column header to sort.

Filters

Dropdown filter to show active, inactive, or all users.

Actions

Edit and Delete buttons for each row with custom click handlers.

Bulk Actions

Select multiple rows and delete them at once, or export to CSV.

Using in Blade

Render the complete table:
<livewire:tables.users-table />

Real-World Product Table Example

Here’s a real example from the demo application showing advanced features:
public function columns(): array
{
    return [
        ImageColumn::make('image_url')
            ->label('Image')
            ->dimensions(80, 80)
            ->alt('name'),

        TextColumn::make('name')
            ->label('Product')
            ->sortable()
            ->searchable(),

        TextColumn::make('sku')
            ->label('SKU')
            ->sortable()
            ->searchable(),

        TextColumn::make('category')
            ->label('Category')
            ->sortable()
            ->searchable(),

        TextColumn::make('price')
            ->label('Price')
            ->sortable()
            ->headerClass('text-right bg-green-50 text-green-700')
            ->cellClass('text-right font-semibold')
            ->format(fn ($value) => '$'.number_format((float) $value, 2)),

        TextColumn::make('stock')
            ->label('Stock')
            ->sortable()
            ->headerClass('text-right')
            ->cellClass('text-right')
            ->format(fn ($value) => number_format((int) $value)),

        BooleanColumn::make('active')
            ->label('Status')
            ->sortable()
            ->labels('Active', 'Inactive'),

        DateColumn::make('release_date')
            ->label('Released')
            ->sortable()
            ->format('M d, Y'),
    ];
}

Configuration Options

Customize table behavior in the configure() method:
public function configure(): void
{
    // Pagination
    $this->setDefaultPerPage(25);
    $this->setPerPageOptions([10, 25, 50, 100]);
    
    // Search
    $this->setSearchDebounce(300); // milliseconds
    
    // Sorting
    $this->setDefaultSortDirection('desc');
    
    // Messages
    $this->setEmptyMessage('No records found.');
    
    // Styling
    $this->setHeadClass('bg-gray-50');
    $this->setBodyClass('divide-y');
    $this->setRowClass(fn($row) => $row->is_urgent ? 'bg-red-50' : '');
}

Key Features Demonstrated

Column Types

  • TextColumn — Display and format text data
  • BooleanColumn — Show true/false with custom labels
  • DateColumn — Format dates with custom patterns
  • ImageColumn — Display images with lightbox support
  • ActionColumn — Add buttons with click handlers

Filter Types

  • TextFilter — Free-text input with custom query logic
  • SelectFilter — Dropdown with single or multiple selection
  • BooleanFilter — Checkbox for yes/no filtering
  • NumberRangeFilter — Min/max range inputs
  • DateRangeFilter — Date range picker

Bulk Actions

  • Selection Model — Exclusion-based (instant select-all across pages)
  • Custom Actions — Define any action method
  • CSV Export — Built-in exportCsvAuto() method
Bulk action methods receive selected IDs via $this->getSelectedIds(). Always validate and authorize these operations.

Next Steps

You now have a fully functional data table. Explore these guides to learn more:

Columns

Learn about all column types and formatting options

Filters

Master all filter types including dependent filters

Bulk Actions

Implement custom bulk operations and CSV exports

Configuration

Explore all configuration options and customization

Build docs developers (and LLMs) love