| Install | |
|---|---|
composer require modus-digital/livewire-datatables |
|
| Latest Version: | 2.0.2 |
| PHP: | ^8.3 |
A modern, feature-rich Livewire Datatable component for the TALL stack (Tailwind CSS, Alpine.js, Laravel, Livewire). Built with modularity, performance, and developer experience in mind.
| Requirement | Version |
|---|---|
| PHP | ^8.3 |
| Laravel | ^11.0 or ^12.0 |
| Livewire | ^3.0 |
| Tailwind CSS | ^4.0 |
| Alpine.js | ^3.0 |
Install the package via Composer:
composer require modus-digital/livewire-datatables
The package will automatically register its service provider.
To customize the table appearance, publish the views:
php artisan vendor:publish --tag="livewire-datatables-views"
This publishes all Blade templates to resources/views/vendor/livewire-datatables/.
To customize the package, you can publish the config file:
php artisan vendor:publish --tag="livewire-datatables-config"
This publishes a config file to config/livewire-datatables.php
To automatically source the frontend using tailwind, include the following files to the app.css
@source '../../vendor/modus-digital/livewire-datatables/resources/**/*.blade.php';
@source '../../vendor/modus-digital/livewire-datatables/src/**/*.php';
Use the built-in Artisan command to scaffold a new table:
php artisan make:table UsersTable --model=App\\Models\\User
Or create one manually:
<?php
declare(strict_types=1);
namespace App\Livewire\Tables;
use App\Models\User;
use ModusDigital\LivewireDatatables\Livewire\Table;
use ModusDigital\LivewireDatatables\Columns\Column;
use ModusDigital\LivewireDatatables\Columns\TextColumn;
use ModusDigital\LivewireDatatables\Filters\SelectFilter;
class UsersTable extends Table
{
protected string $model = User::class;
protected function columns(): array
{
return [
TextColumn::make('Name')
->field('name')
->sortable()
->searchable(),
TextColumn::make('Email')
->field('email')
->sortable()
->searchable(),
TextColumn::make('Status')
->field('status')
->badge()
->sortable(),
TextColumn::make('Created')
->field('created_at')
->sortable()
->format(fn($value) => $value->diffForHumans()),
];
}
protected function filters(): array
{
return [
SelectFilter::make('Status')
->options([
'active' => 'Active',
'inactive' => 'Inactive',
'banned' => 'Banned',
])
->multiple(), // <-- This is optional
];
}
}
<livewire:users-table />
De basis met alle kernopties:
Column::make('Name')
->field('name') // Database field (ook: 'relation.field')
->sortable() // Kolom sorteerbaar maken
->searchable() // Opnemen in globale zoek
->hidden() // Verbergen
->width('150px') // CSS breedte (bv. '150px', '20%')
->align('center') // 'left' | 'center' | 'right'
->view('custom.cell') // Custom Blade view voor de cel
->sortField('users.name') // Aparte sorteer-field (optioneel)
->format(fn ($value, $record) => strtoupper((string) $value));
Extra’s voor tekstweergave:
TextColumn::make('Description')
->field('description')
->limit(50) // Tekst afkappen
->badge('blue') // Badge tonen (kleur vast of via Closure)
->fullWidth(); // Badge over volle breedte
IconColumn::make('Status')
->field('is_active')
->icon(fn ($record) => $record->is_active ? 'fa-check' : 'fa-times')
->count(fn ($record) => $record->notifications_count);
ImageColumn::make('Avatar')
->field('avatar_url')
->src(fn ($record) => $record->getAvatarUrl())
->circle(); // Rond i.p.v. vierkant
Relatievelden gebruik je met dot-notatie in field:
Column::make('Department')
->field('department.name') // Relationele kolom
->sortable();
Voor aangepaste SQL sortering via een andere kolom:
Column::make('Department')
->field('department.name')
->sortField('departments.name');
use ModusDigital\LivewireDatatables\Filters\TextFilter;
TextFilter::make('Name')
->field('name')
->placeholder('Search names...')
->contains(); // ook: ->exact(), ->startsWith(), ->endsWith()
use ModusDigital\LivewireDatatables\Filters\SelectFilter;
SelectFilter::make('Status')
->field('status')
->options([
'active' => 'Active Users',
'inactive' => 'Inactive Users',
'banned' => 'Banned Users',
])
->placeholder('All Statuses')
->multiple();
use ModusDigital\LivewireDatatables\Filters\DateFilter;
DateFilter::make('Created')
->field('created_at')
->range() // datumbereik (from/to)
->format('Y-m-d');
Filters werken ook op relatievelden (field('relation.attribute')). Indien een veld een Eloquent attribute/accessor is, valt filtering terug op PHP (na ophalen) voor correcte resultaten.
Rijselectie inschakelen en gebruiken:
class UsersTable extends Table
{
// Of via config('livewire-datatables.checkboxes')
public bool $showSelection = true;
}
Geselecteerde IDs vind je in $this->selected (array). Combineer dit met een globale actie om bulk-operaties te doen (zie hieronder).
Voeg rijacties met callbacks toe:
use ModusDigital\LivewireDatatables\Actions\RowAction;
protected function rowActions(): array
{
return [
RowAction::make('edit', 'Edit')
->class('text-blue-600')
->callback(fn ($row, $table) => redirect()->route('users.edit', $row)),
RowAction::make('delete', 'Delete')
->confirm('Delete this user?')
->callback(function ($row) {
$row->delete();
session()->flash('message', 'User deleted successfully.');
}),
];
}
Je kunt zichtbaarheid conditioneel maken met ->visible(fn ($row) => ...) en een ->icon() string meegeven.
Header-acties met callback (handig voor bulk op $this->selected):
use ModusDigital\LivewireDatatables\Actions\Action;
protected function actions(): array
{
return [
Action::make('create', 'Add User')
->class('bg-blue-600 hover:bg-blue-700 text-white')
->callback(fn ($table) => redirect()->route('users.create')),
Action::make('delete-selected', 'Delete Selected')
->class('bg-red-600 hover:bg-red-700 text-white')
->confirm('Delete all selected users?')
->callback(function ($table) {
$ids = $table->selected;
if (! empty($ids)) {
\App\Models\User::whereIn('id', $ids)->delete();
$table->deselectAll();
}
}),
];
}
Maak hele rijen klikbaar door showRecord te overriden:
public function showRecord(string|int $id): void
{
// Bijvoorbeeld:
redirect()->route('users.show', $id);
}
class UsersTable extends Table
{
public int $perPage = 25; // Standaard page size
protected array $perPageOptions = [10, 25, 50, 100];
}
class UsersTable extends Table
{
protected bool $searchable = true;
protected string $searchPlaceholder = 'Search users...';
}
Publiceer de views en pas resources/views/vendor/livewire-datatables/partials/empty-state.blade.php aan:
<h3 class="mt-2 text-sm font-medium">No records</h3>
<p class="mt-1 text-sm">Try adjusting your filters.</p>
protected function query(): Builder
{
return $this->getModel()
->query()
->with(['profile', 'roles']);
}
Gebruik dot‑notatie in field('relation.column'). Voor sorting over relaties gebruik je ->sortField('related_table.column'). Wanneer je sorteert op een attribute/accessor, wordt automatisch in PHP gesorteerd na ophalen.
The package includes full dark mode support using Tailwind's dark: variants. Ensure your project has dark mode configured:
@source '../../vendor/modus-digital/livewire-datatables/resources/views/**/*.blade.php';
Create custom cell views for complex content:
Column::make('Actions')
->view('components.user-actions')
->width('w-32'),
<!-- resources/views/components/user-actions.blade.php -->
<div class="flex space-x-2">
<button wire:click="editUser({{ $record->id }})" class="text-blue-600">
Edit
</button>
<button wire:click="deleteUser({{ $record->id }})" class="text-red-600">
Delete
</button>
</div>
Available badge colors for TextColumn:
gray (default)redyellowgreenblueindigopurplepinkTextColumn::make('Status')
->badge(fn($record) => match($record->status) {
'active' => 'green',
'pending' => 'yellow',
'banned' => 'red',
default => 'gray'
});
The package follows a modular trait-based architecture:
HasColumns - Column management and rendering (120 lines)HasFilters - Filter functionality and application (149 lines)HasPagination - Pagination configuration (67 lines)HasSorting - Sorting logic and state management (132 lines)HasRowSelection - Row selection and bulk actions (142 lines)HasRowActions - Individual row action handling (92 lines)HasActions - Global header actions (59 lines)Each trait is focused, testable, and can be understood independently.
The package includes comprehensive tests using Pest 3:
# Run all tests
composer test
# Run static analysis
composer analyse
# Fix code style
composer format
The package uses several tools to maintain high code quality:
composer testcomposer formatcomposer analyseSee CHANGELOG.md for recent changes and version history.
The MIT License (MIT). Please see License File for more information.