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

nalletje/livewire-tables

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require nalletje/livewire-tables
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Nalletje\LivewireTables\LivewireTablesServiceProvider"
    
  2. Basic Usage:

    • Create a Livewire component:
      php artisan make:livewire Admin/UsersTable
      
    • Extend Nalletje\LivewireTables\Traits\HasLivewireTables in your component:
      use Nalletje\LivewireTables\Traits\HasLivewireTables;
      
      class UsersTable extends Component
      {
          use HasLivewireTables;
      
          public function tableQuery()
          {
              return User::query();
          }
      
          public function tableColumns()
          {
              return [
                  'id' => 'ID',
                  'name' => 'Name',
                  'email' => 'Email',
              ];
          }
      }
      
  3. First Render:

    • Add the table view to your Blade template:
      <livewire:admin.users-table />
      
    • The package auto-generates a Bootstrap 5 table with search, pagination, and basic sorting.

First Use Case: Quick Data Listing

// In your Livewire component
public function tableQuery()
{
    return User::query()
        ->where('active', true)
        ->orderBy('name');
}

public function tableColumns()
{
    return [
        'name' => 'Name',
        'email' => 'Email',
        'created_at' => 'Joined',
    ];
}

Result: A table with search, pagination, and sortable columns. Columns like created_at are auto-formatted.


Implementation Patterns

1. Query Building

  • Dynamic Query Modifiers: Use tableQuery() to return a base query. The package handles:

    • Search (search input in the UI)
    • Pagination (auto-injected)
    • Sorting (clickable column headers)
    public function tableQuery()
    {
        $query = User::query()
            ->with('roles') // Eager load relations
            ->when($this->search, fn($q) => $q->where('name', 'like', "%{$this->search}%"));
    
        return $query;
    }
    
  • Filter Integration: Define filters in tableFilters():

    public function tableFilters()
    {
        return [
            'active' => [
                'type' => 'select',
                'label' => 'Status',
                'options' => [
                    'all' => 'All',
                    'active' => 'Active',
                    'inactive' => 'Inactive',
                ],
                'default' => 'all',
            ],
        ];
    }
    

    Filter Logic:

    public function tableQuery()
    {
        $query = User::query();
        if ($this->active === 'active') {
            $query->where('active', true);
        } elseif ($this->active === 'inactive') {
            $query->where('active', false);
        }
        return $query;
    }
    

2. Actions (Row Operations)

  • Single/Multi-Row Actions: Define actions in tableActions():

    public function tableActions()
    {
        return [
            'edit' => [
                'label' => 'Edit',
                'icon' => 'fas fa-edit',
                'handler' => fn($user) => redirect()->route('users.edit', $user),
            ],
            'delete' => [
                'label' => 'Delete',
                'icon' => 'fas fa-trash',
                'handler' => fn($user) => $this->deleteUser($user),
                'confirm' => 'Are you sure?',
            ],
            'bulk_delete' => [
                'label' => 'Delete Selected',
                'icon' => 'fas fa-trash',
                'handler' => fn($users) => $this->deleteUsers($users),
                'confirm' => 'Delete selected users?',
                'multi' => true, // Enable for bulk actions
            ],
        ];
    }
    
  • Form-Based Actions:

    public function tableActions()
    {
        return [
            'promote' => [
                'label' => 'Promote',
                'icon' => 'fas fa-user-shield',
                'handler' => fn($user) => $this->render('promote-modal', ['user' => $user]),
                'form' => true, // Renders a modal with form
            ],
        ];
    }
    

    Handler:

    public function promoteUser($user, $role)
    {
        $user->roles()->attach($role);
        return new Message('User promoted successfully!');
    }
    

3. Column Customization

  • Transform Column Data:

    public function tableColumns()
    {
        return [
            'name' => 'Name',
            'email' => fn($user) => \Illuminate\Support\HtmlString::from("<a href='mailto:{$user->email}'>{$user->email}</a>"),
            'roles' => fn($user) => $user->roles->implode('name', ', '),
        ];
    }
    
  • Conditional Columns:

    public function tableColumns()
    {
        return [
            'name' => 'Name',
            'active' => fn($user) => $user->active
                ? '<span class="badge bg-success">Active</span>'
                : '<span class="badge bg-danger">Inactive</span>',
        ];
    }
    

4. Route Buttons

Add buttons above/below the table:

public function tableButtons()
{
    return [
        'create' => [
            'label' => 'Add User',
            'icon' => 'fas fa-plus',
            'route' => route('users.create'),
            'class' => 'btn-primary',
        ],
        'export' => [
            'label' => 'Export',
            'icon' => 'fas fa-file-export',
            'handler' => fn() => $this->exportUsers(),
        ],
    ];
}

5. Integration with Spatie Permissions (Optional)

public function tableQuery()
{
    return User::query()
        ->when($this->hasPermission('view-inactive-users'), fn($q) => $q->where('active', false));
}

Gotchas and Tips

Pitfalls

  1. Action Handler Returns:

    • Breaking Change (v0.1.0): Handlers must return a Message object (not a string).
      return new \Nalletje\LivewireTables\Message('Success!');
      
    • Fix: Update old handlers to use the Message class.
  2. Relation Loading:

    • Issue: Forgetting to eager-load relations causes N+1 queries.
      // Bad
      return User::query(); // Missing `with('roles')`
      
      // Good
      return User::with('roles')->query();
      
  3. Filter Defaults:

    • Gotcha: Filter defaults in tableFilters() must match the query logic.
      // If default is 'all', ensure your query handles it:
      if ($this->active === 'all') {
          // No where clause
      }
      
  4. Bootstrap 5 Dependencies:

    • Error: Missing Bootstrap 5 CSS/JS breaks styling.
      @vite(['resources/css/app.css', 'resources/js/app.js'])
      
      Ensure bootstrap@5 is included.

Debugging Tips

  1. Query Inspection: Use Laravel Debugbar or dd($this->tableQuery()->toSql()) to verify queries.

  2. Action Debugging: Add dd($user) in handlers to inspect passed data:

    public function deleteUser($user)
    {
        dd($user); // Debug payload
        $user->delete();
        return new Message('Deleted!');
    }
    
  3. Filter State: Dump filter values in mount():

    public function mount()
    {
        dd($this->active, $this->search); // Check current state
    }
    

Extension Points

  1. Custom Views: Override the default table view by publishing assets:

    php artisan vendor:publish --tag=livewire-tables-views
    

    Modify resources/views/vendor/livewire-tables/table.blade.php.

  2. Add Select2 Filters: Extend the package by adding Select2 support:

    public function tableFilters()
    {
        return [
            'role' => [
                'type' => 'select2', // Custom type
                'label' => 'Role',
                'options' => Role::pluck('name', 'id'),
                'ajax' => true, // Enable AJAX for large datasets
            ],
        ];
    }
    

    Note: Requires manual JS integration (see Select2 docs).

  3. Bulk Action Confirmation: Customize bulk

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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle