Laravel Livewire Tables Documentation

🎉 Enjoying this package? Consider sponsoring me on GitHub or buying me a beer.

This is the documentation for v1 but the latest version is v3. You can switch versions in the menu at the top. Check your current version with the following command:

composer show rappasoft/laravel-livewire-tables

Advanced Example

The DataTable plugin has many advanced features from bulk exporting, custom views, custom searching/sorting, filtering, column selection, drag & drop reordering, etc.

There will be sections of the wiki to go into these in detail, but this is an example of a table with a custom row, filters, and bulk exporting:

1<?php
2 
3namespace App\Http\Livewire\Admin\User;
4 
5use App\Domains\Auth\Models\User;
6use App\Domains\User\Exports\UserExport;
7use Illuminate\Database\Eloquent\Builder;
8use Rappasoft\LaravelLivewireTables\DataTableComponent;
9use Rappasoft\LaravelLivewireTables\Views\Column;
10use Rappasoft\LaravelLivewireTables\Views\Filter;
11 
12class UsersTable extends DataTableComponent
13{
14 
15 public array $sortNames = [
16 'email_verified_at' => 'Verified',
17 'two_factor_secret' => '2FA',
18 ];
19 
20 public array $filterNames = [
21 'type' => 'User Type',
22 'verified' => 'E-mail Verified',
23 '2fa' => 'Two Factor Authentication',
24 ];
25 
26 public array $bulkActions = [
27 'exportSelected' => 'Export',
28 ];
29 
30 protected string $pageName = 'users';
31 protected string $tableName = 'users';
32 
33 public function exportSelected()
34 {
35 if ($this->selectedRowsQuery->count() > 0) {
36 return (new UserExport($this->selectedRowsQuery))->download($this->tableName.'.xlsx');
37 }
38 
39 // Not included in package, just an example.
40 $this->notify(__('You did not select any users to export.'), 'danger');
41 }
42 
43 public function filters(): array
44 {
45 return [
46 'type' => Filter::make('User Type')
47 ->select([
48 '' => 'Any',
49 User::TYPE_ADMIN => 'Administrators',
50 User::TYPE_USER => 'Users',
51 ]),
52 'active' => Filter::make('Active')
53 ->select([
54 '' => 'Any',
55 'yes' => 'Yes',
56 'no' => 'No',
57 ]),
58 'verified' => Filter::make('E-mail Verified')
59 ->select([
60 '' => 'Any',
61 'yes' => 'Yes',
62 'no' => 'No',
63 ]),
64 '2fa' => Filter::make('Two Factor Authentication')
65 ->select([
66 '' => 'Any',
67 'enabled' => 'Enabled',
68 'disabled' => 'Disabled',
69 ]),
70 ];
71 }
72 
73 public function columns(): array
74 {
75 return [
76 Column::make('Type')
77 ->sortable()
78 ->addClass('hidden md:table-cell'),
79 Column::make('Name')
80 ->sortable(),
81 Column::make('E-mail', 'email')
82 ->sortable(),
83 Column::make('Active')
84 ->sortable()
85 ->addClass('hidden md:table-cell'),
86 Column::make('Verified', 'email_verified_at')
87 ->sortable()
88 ->addClass('hidden md:table-cell'),
89 Column::make('2FA', 'two_factor_secret')
90 ->sortable()
91 ->addClass('hidden md:table-cell'),
92 Column::blank(),
93 ];
94 }
95 
96 public function query(): Builder
97 {
98 return User::query()
99 ->when($this->getFilter('search'), fn ($query, $search) => $query->search($search))
100 ->when($this->getFilter('type'), fn ($query, $type) => $query->where('type', $type))
101 ->when($this->getFilter('active'), fn ($query, $active) => $query->where('active', $active === 'yes'))
102 ->when($this->getFilter('verified'), fn ($query, $verified) => $verified === 'yes' ? $query->whereNotNull('email_verified_at') : $query->whereNull('email_verified_at'))
103 ->when($this->getFilter('2fa'), fn ($query, $twoFactor) => $twoFactor === 'enabled' ? $query->whereNotNull('two_factor_secret') : $query->whereNull('two_factor_secret'));
104 }
105 
106 public function rowView(): string
107 {
108 return 'location.to.my.row.view';
109 }
110}

It's associated custom row:

row.blade.php

1<x-livewire-tables::table.cell class="hidden md:table-cell">
2 <div>
3 @if ($row->isAdmin())
4 <x-badges.success>{{ ucfirst($row->type) }}</x-badges.success>
5 @else
6 <x-badges.default>{{ ucfirst($row->type) }}</x-badges.default>
7 @endif
8 </div>
9</x-livewire-tables::table.cell>
10 
11<x-livewire-tables::table.cell>
12 <div class="flex items-center">
13 @if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
14 <div wire:key="profile-picture-{{ $row->id }}" class="flex-shrink-0 h-10 w-10">
15 <img class="h-10 w-10 rounded-full" src="{{ $row->profile_photo_url }}" alt="{{ $row->name }}" />
16 </div>
17 @endif
18 
19 <div class="@if (Laravel\Jetstream\Jetstream::managesProfilePhotos()) ml-4 @endif">
20 <div class="text-sm font-medium text-gray-900">
21 {{ $row->name }}
22 </div>
23 
24 @if($row->timezone)
25 <div wire:key="timezone-{{ $row->id }}" class="text-sm text-gray-500">
26 {{ str_replace('_', ' ', $row->timezone) }}
27 </div>
28 @endif
29 </div>
30 </div>
31</x-livewire-tables::table.cell>
32 
33<x-livewire-tables::table.cell>
34 <p class="text-blue-400 truncate">
35 <a href="mailto:{{ $row->email }}" class="hover:underline">{{ $row->email }}</a>
36 </p>
37</x-livewire-tables::table.cell>
38 
39<x-livewire-tables::table.cell class="hidden md:table-cell">
40 <div>
41 @if ($row->isActive())
42 <x-badges.success>@lang('Yes')</x-badges.success>
43 @else
44 <x-badges.danger>@lang('No')</x-badges.danger>
45 @endif
46 </div>
47</x-livewire-tables::table.cell>
48 
49<x-livewire-tables::table.cell class="hidden md:table-cell">
50 <div>
51 @if ($row->isVerified())
52 <x-badges.success>@lang('Yes')</x-badges.success>
53 @else
54 <x-badges.danger>@lang('No')</x-badges.danger>
55 @endif
56 </div>
57</x-livewire-tables::table.cell>
58 
59<x-livewire-tables::table.cell class="hidden md:table-cell">
60 <div>
61 @if ($row->twoFactorEnabled())
62 <x-badges.success>@lang('Enabled')</x-badges.success>
63 @else
64 <x-badges.danger>@lang('Disabled')</x-badges.danger>
65 @endif
66 </div>
67</x-livewire-tables::table.cell>
68 
69<x-livewire-tables::table.cell>
70 <a href="#" wire:click.prevent="manage({{ $row->id }})" class="text-primary-600 font-medium hover:text-primary-900">Manage</a>
71</x-livewire-tables::table.cell>