Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Tables Laravel Package

timolake/livewire-tables

timolake/livewire-tables provides reusable Livewire components for building interactive, sortable, searchable data tables in Laravel. Create table views with pagination, filters, and column definitions, keeping server-side rendering with a reactive UI and minimal boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package

    composer require timolake/livewire-tables
    

    Ensure your project uses Livewire 3.x and Laravel 10/11.

  2. Create a Basic Table Class Define a Table class for your model (e.g., app/Tables/UserTable.php):

    use Timolake\LivewireTables\Table;
    
    class UserTable extends Table
    {
        public function configure()
        {
            $this->setPrimaryKey('id');
            $this->setSearch(['name', 'email']);
            $this->setColumns(['id', 'name', 'email']);
            $this->setPagination(10); // Optional: default 15
        }
    
        public function query()
        {
            return User::query();
        }
    }
    
  3. Render the Table in Blade Use the @livewire directive to embed the table:

    @livewire('user-table', ['table' => \App\Tables\UserTable::class])
    
  4. Create a Livewire Component Generate a Livewire component to host the table:

    php artisan make:livewire UserTable
    

    Update the generated UserTable.php:

    public $table;
    
    public function mount($table)
    {
        $this->table = $table;
    }
    
    public function render()
    {
        return view('livewire.user-table');
    }
    
  5. Update the Livewire View Edit resources/views/livewire/user-table.blade.php:

    <div>
        {!! $this->table->render() !!}
    </div>
    

First Use Case

Replace a manual paginated table loop with the package’s built-in functionality. For example: Before:

<table>
    @foreach ($users->paginate(10) as $user)
        <tr>
            <td>{{ $user->id }}</td>
            <td>{{ $user->name }}</td>
            <td>{{ $user->email }}</td>
        </tr>
    @endforeach
</table>

After:

@livewire('user-table', ['table' => \App\Tables\UserTable::class])

The package handles pagination, search, and sorting automatically.


Implementation Patterns

Core Workflows

  1. Define Table Structure Use the configure() method to set up columns, searchable fields, and pagination:

    public function configure()
    {
        $this->setPrimaryKey('id');
        $this->setSearch(['name', 'email', 'created_at']); // Search across fields
        $this->setColumns([
            'id' => 'ID',
            'name' => 'Name',
            'email' => 'Email',
            'created_at' => 'Created At',
        ]);
        $this->setSortable(['name', 'email', 'created_at']); // Explicitly set sortable columns
        $this->setPagination(20);
    }
    
  2. Customize Column Rendering Override column rendering in the configure() method or use Blade views:

    $this->setColumns([
        'id' => 'ID',
        'name' => function ($value, $row) {
            return Str::upper($value); // Custom logic
        },
        'email' => LivewireView::make('tables.email-column', ['user' => $row]),
    ]);
    

    Create a Blade view (resources/views/tables/email-column.blade.php):

    <a href="mailto:{{ $user->email }}">{{ $user->email }}</a>
    
  3. Add Row Actions Define actions in configure() and render them in the table:

    public function configure()
    {
        $this->addAction('view', 'View', 'livewire.view-user', ['user' => $this->getKey()]);
        $this->addAction('edit', 'Edit', 'livewire.edit-user', ['user' => $this->getKey()]);
    }
    

    The package renders action buttons by default. Customize the view:

    @foreach ($this->table->getActions() as $action)
        <td>
            {!! $action->render() !!}
        </td>
    @endforeach
    
  4. Filtering and Advanced Queries Use the query() method to build complex queries:

    public function query()
    {
        return User::query()
            ->when($this->getSearch(), function ($query) {
                return $query->where(function ($q) {
                    $q->where('name', 'like', "%{$this->getSearch()}%")
                      ->orWhere('email', 'like', "%{$this->getSearch()}%");
                });
            })
            ->when($this->getSort(), function ($query) {
                $query->orderBy($this->getSort()[0], $this->getSort()[1]);
            });
    }
    
  5. Bulk Actions Add bulk actions via the addBulkAction() method:

    public function configure()
    {
        $this->addBulkAction('delete', 'Delete Selected', 'livewire.delete-users', [
            'users' => $this->getSelectedKeys(),
        ]);
    }
    

    Render the bulk action dropdown in Blade:

    @if ($this->table->hasBulkActions())
        <div>
            {!! $this->table->renderBulkActions() !!}
        </div>
    @endif
    

Integration Tips

  1. Reuse Tables Across Components Create a base Table class for shared configurations:

    abstract class BaseTable extends Table
    {
        public function configure()
        {
            $this->setPagination(25);
            $this->setSearchDebounce(500); // Debounce search input
        }
    }
    
  2. Leverage Traits for Shared Logic Use provided traits (e.g., PaginationTrait) or create custom ones:

    use Timolake\LivewireTables\Traits\PaginationTrait;
    
    class UserTable extends Table
    {
        use PaginationTrait;
    
        public function configure()
        {
            $this->setPagination(10);
        }
    }
    
  3. Customize Styling Override the default table view (resources/views/vendor/livewire-tables/table.blade.php):

    <table class="min-w-full divide-y divide-gray-200">
        <!-- Customize table classes and structure -->
    </table>
    

    Use Tailwind CSS or your preferred CSS framework for styling.

  4. Session Persistence The package automatically persists search, sort, and pagination states in the session. Customize the session key:

    public function configure()
    {
        $this->setSessionKey('custom_user_table_state');
    }
    
  5. Lazy Loading for Large Datasets For tables with >10K rows, implement cursor pagination:

    public function query()
    {
        return User::query()
            ->cursor()
            ->when($this->getSearch(), function ($query) {
                // Add search logic
            });
    }
    
  6. Integration with Livewire Actions Trigger Livewire actions from table events (e.g., row clicks):

    public function render()
    {
        return view('livewire.user-table', [
            'table' => $this->table,
            'onRowClick' => function ($row) {
                $this->emit('rowClicked', $row->id);
            },
        ]);
    }
    

    Listen for events in the parent component:

    protected $listeners = ['rowClicked'];
    
    public function rowClicked($id)
    {
        // Handle row click logic
    }
    

Gotchas and Tips

Pitfalls

  1. Session State Conflicts

    • Issue: Multiple tables with the same session key may interfere.
    • Fix: Always set a unique setSessionKey() for each table:
      $this->setSessionKey('user_table_state');
      
  2. Performance with Large Datasets

    • Issue: Eloquent queries without proper indexing or pagination can cause timeouts.
    • Fix:
      • Add database indexes to searchable/sortable columns.
      • Use cursor() for large datasets:
        return User::query()->cursor()->paginate(100);
        
      • Limit the number of rows fetched per page.
  3. Search Not Working as Expected

    • Issue: Case-sensitive searches or special characters may break queries.
    • Fix:
      • Use LIKE with wildcards:
        $query->where('name', 'like', "%{$search}%");
        
      • For case-insensitive search (PostgreSQL):
        $query->where('name', 'ILIKE', "%{$search}%");
        
  4. Sorting Not Persisting

    • Issue: Sort direction or column may reset unexpectedly.
    • Fix: Ensure
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views
spatie/ignition-contracts