- Creating Columns
- Relationships
- Available Methods
- Other Column Types
- Column Selection
- Secondary Header
- Footer
- Reusable Columns
- Anonymous Columns
- Styling
- Standard Column
- Array Columns (beta)
- Avg Columns (beta)
- Boolean Columns
- Button Group Columns
- Color Columns
- Component Columns
- Count Columns (beta)
- Date Columns
- Icon Columns (beta)
- Image Columns
- Increment Column (beta)
- Link Columns
- Livewire Component (beta)
- Sum Columns (beta)
- View Component Columns
- Wire Link Column (beta)
- Introduction
- Creating Filters
- Applying Filters
- Available Methods
- Available Component Methods
- Available Filter Methods
- Introduction
- Boolean Filters (beta)
- Date Filters
- DateRange Filters
- DateTime Filters
- Multi-Select Dropdown Filters
- Multi-Select Filters
- NumberRange Filters
- Number Filters
- Select Filters
- Text Filters
- Livewire Custom Filter (Beta)
- Refreshing
- Loading Placeholder
- Multiple Tables Same Page
- Actions (beta)
- Adding Custom Markup
- Debugging
- Saving Table State
- Lifecycle Hooks
- Hiding The Table (beta)
- One Of Many Example
- Tools
Getting Started
Usage
DataTable
Columns
Column Types
Rows
Sorting
Pagination
Search
Bulk Actions
Filters
Filter Types
Reordering
Secondary Header
Footer
Examples
Misc.
Sponsored
Advanced Usage
Examples
🎉 Enjoying this package? Consider sponsoring me on GitHub or buying me a beer.
This is the documentation for v3. You can switch versions in the menu on the left/at the top. Check your current version with the following command:
composer show rappasoft/laravel-livewire-tables
Advanced Example
1<?php 2 3namespace App\Livewire; 4 5use App\Models\{Tag,User}; 6use Illuminate\Database\Eloquent\Builder; 7use Rappasoft\LaravelLivewireTables\DataTableComponent; 8use Rappasoft\LaravelLivewireTables\Views\Column; 9use Rappasoft\LaravelLivewireTables\Views\Columns\{BooleanColumn, ImageColumn}; 10use Rappasoft\LaravelLivewireTables\Views\Filters\{DateFilter, MultiSelectFilter, SelectFilter}; 11 12class UsersTable extends DataTableComponent 13{ 14 public string $tableName = 'users'; 15 public array $users = []; 16 17 public $columnSearch = [ 18 'name' => null, 19 'email' => null, 20 ]; 21 22 public function configure(): void 23 { 24 $this->setPrimaryKey('id') 25 ->setReorderEnabled() 26 ->setSingleSortingDisabled() 27 ->setHideReorderColumnUnlessReorderingEnabled() 28 ->setFilterLayoutSlideDown() 29 ->setRememberColumnSelectionDisabled() 30 ->setSecondaryHeaderTrAttributes(function($rows) { 31 return ['class' => 'bg-gray-100']; 32 }) 33 ->setSecondaryHeaderTdAttributes(function(Column $column, $rows) { 34 if ($column->isField('id')) { 35 return ['class' => 'text-red-500']; 36 } 37 38 return ['default' => true]; 39 }) 40 ->setFooterTrAttributes(function($rows) { 41 return ['class' => 'bg-gray-100']; 42 }) 43 ->setFooterTdAttributes(function(Column $column, $rows) { 44 if ($column->isField('name')) { 45 return ['class' => 'text-green-500']; 46 } 47 48 return ['default' => true]; 49 }) 50 ->setUseHeaderAsFooterEnabled() 51 ->setHideBulkActionsWhenEmptyEnabled(); 52 } 53 54 public function columns(): array 55 { 56 return [ 57 ImageColumn::make('Avatar') 58 ->location(function($row) { 59 return asset('img/logo-'.$row->id.'.png'); 60 }) 61 ->attributes(function($row) { 62 return [ 63 'class' => 'w-8 h-8 rounded-full', 64 ]; 65 }), 66 Column::make('Order', 'sort') 67 ->sortable() 68 ->collapseOnMobile() 69 ->excludeFromColumnSelect(), 70 Column::make('ID', 'id') 71 ->sortable() 72 ->setSortingPillTitle('Key') 73 ->setSortingPillDirections('0-9', '9-0') 74 ->secondaryHeader(function($rows) { 75 return $rows->sum('id'); 76 }) 77 ->html(), 78 Column::make('Name') 79 ->sortable() 80 ->searchable() 81 ->view('tables.cells.actions') 82 ->secondaryHeader(function() { 83 return view('tables.cells.input-search', ['field' => 'name', 'columnSearch' => $this->columnSearch]); 84 }) 85 ->html(), 86 Column::make('E-mail', 'email') 87 ->sortable() 88 ->searchable() 89 ->secondaryHeader(function() { 90 return view('tables.cells.input-search', ['field' => 'email', 'columnSearch' => $this->columnSearch]); 91 }), 92 Column::make('Address', 'address.address') 93 ->sortable() 94 ->searchable() 95 ->collapseOnTablet(), 96 Column::make('Address Group', 'address.group.name') 97 ->sortable() 98 ->searchable() 99 ->collapseOnTablet(),100 Column::make('Group City', 'address.group.city.name')101 ->sortable()102 ->searchable()103 ->collapseOnTablet(),104 BooleanColumn::make('Active')105 ->sortable()106 ->collapseOnMobile(),107 Column::make('Verified', 'email_verified_at')108 ->sortable()109 ->collapseOnTablet(),110 Column::make('Tags')111 ->label(fn($row) => $row->tags->pluck('name')->implode(', '))112 ];113 }114 115 public function filters(): array116 {117 return [118 MultiSelectFilter::make('Tags')119 ->options(120 Tag::query()121 ->orderBy('name')122 ->get()123 ->keyBy('id')124 ->map(fn($tag) => $tag->name)125 ->toArray()126 )->filter(function(Builder $builder, array $values) {127 $builder->whereHas('tags', fn($query) => $query->whereIn('tags.id', $values));128 })129 ->setFilterPillValues([130 '3' => 'Tag 1',131 ]),132 SelectFilter::make('E-mail Verified', 'email_verified_at')133 ->setFilterPillTitle('Verified')134 ->options([135 '' => 'Any',136 'yes' => 'Yes',137 'no' => 'No',138 ])139 ->filter(function(Builder $builder, string $value) {140 if ($value === 'yes') {141 $builder->whereNotNull('email_verified_at');142 } elseif ($value === 'no') {143 $builder->whereNull('email_verified_at');144 }145 }),146 SelectFilter::make('Active')147 ->setFilterPillTitle('User Status')148 ->setFilterPillValues([149 '1' => 'Active',150 '0' => 'Inactive',151 ])152 ->options([153 '' => 'All',154 '1' => 'Yes',155 '0' => 'No',156 ])157 ->filter(function(Builder $builder, string $value) {158 if ($value === '1') {159 $builder->where('active', true);160 } elseif ($value === '0') {161 $builder->where('active', false);162 }163 }),164 SelectFilter::make('Address Group')165 ->options([166 '' => 'All',167 AddressGroup::query()168 ->orderBy('type')169 ->get()170 ->groupBy('type')171 ->map(fn ($addressGroup) => $addressGroup->pluck('type', 'id')->filter())172 ->toArray(),173 ])174 ->filter(function(Builder $builder, string $value) {175 $builder->where('address_groups.type', $value);176 }),177 DateFilter::make('Verified From')178 ->config([179 'min' => '2020-01-01',180 'max' => '2021-12-31',181 ])182 ->filter(function(Builder $builder, string $value) {183 $builder->where('email_verified_at', '>=', $value);184 }),185 DateFilter::make('Verified To')186 ->filter(function(Builder $builder, string $value) {187 $builder->where('email_verified_at', '<=', $value);188 }),189 ];190 }191 192 public function builder(): Builder193 {194 return User::query()195 ->when($this->columnSearch['name'] ?? null, fn ($query, $name) => $query->where('users.name', 'like', '%' . $name . '%'))196 ->when($this->columnSearch['email'] ?? null, fn ($query, $email) => $query->where('users.email', 'like', '%' . $email . '%'));197 }198 199 public function bulkActions(): array200 {201 return [202 'activate' => 'Activate',203 'deactivate' => 'Deactivate',204 ];205 }206 207 public function activate()208 {209 User::whereIn('id', $this->getSelected())->update(['active' => true]);210 211 $this->clearSelected();212 }213 214 public function deactivate()215 {216 User::whereIn('id', $this->getSelected())->update(['active' => false]);217 218 $this->clearSelected();219 }220 221 public function reorder($items): void222 {223 foreach ($items as $item) {224 User::find($item[$this->getPrimaryKey()])->update(['sort' => (int)$item[$this->getDefaultReorderColumn()]]);225 }226 }227}
input-search.blade.php
1@if (config('livewire-tables.theme') === 'tailwind') 2 <div class="flex rounded-md shadow-sm"> 3 <input 4 wire:model.debounce="columnSearch.{{ $field }}" 5 placeholder="Search {{ ucfirst($field) }}" 6 type="text" 7 class="block w-full border-gray-300 rounded-md shadow-sm transition duration-150 ease-in-out sm:text-sm sm:leading-5 dark:bg-gray-800 dark:text-white dark:border-gray-600 @if (isset($columnSearch[$field]) && strlen($columnSearch[$field])) rounded-none rounded-l-md focus:ring-0 focus:border-gray-300 @else focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md @endif" 8 /> 9 10 @if (isset($columnSearch[$field]) && strlen($columnSearch[$field]))11 <span wire:click="$set('columnSearch.{{ $field }}', null)" class="inline-flex items-center px-3 text-gray-500 border border-l-0 border-gray-300 cursor-pointer bg-gray-50 rounded-r-md sm:text-sm dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:hover:bg-gray-600">12 <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">13 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />14 </svg>15 </span>16 @endif17 </div>18@endif19 20@if (config('livewire-tables.theme') === 'bootstrap-4')21 <div class="mb-3 mb-md-0 input-group">22 <input23 wire:model.debounce="columnSearch.{{ $field }}"24 placeholder="Search {{ ucfirst($field) }}"25 type="text"26 class="form-control"27 >28 29 @if (isset($columnSearch[$field]) && strlen($columnSearch[$field]))30 <div class="input-group-append">31 <button wire:click="$set('columnSearch.{{ $field }}', null)" class="btn btn-outline-secondary" type="button">32 <svg style="width:.75em;height:.75em" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">33 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />34 </svg>35 </button>36 </div>37 @endif38 </div>39@endif40 41@if (config('livewire-tables.theme') === 'bootstrap-5')42 <div class="mb-3 mb-md-0 input-group">43 <input44 wire:model.debounce="columnSearch.{{ $field }}"45 placeholder="Search {{ ucfirst($field) }}"46 type="text"47 class="form-control"48 >49 50 @if (isset($columnSearch[$field]) && strlen($columnSearch[$field]))51 <button wire:click="$set('columnSearch.{{ $field }}', null)" class="btn btn-outline-secondary" type="button">52 <svg style="width:.75em;height:.75em" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">53 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />54 </svg>55 </button>56 @endif57 </div>58@endif