Installation:
composer require arm092/livewire-datatables
Publish assets (optional but recommended for customization):
php artisan vendor:publish --provider="Arm092\LivewireDatatables\LivewireDatatablesServiceProvider"
First Component:
Create a Livewire component targeting a model (e.g., User):
php artisan make:livewire Admin/UserTable
Update the component class (app/Http/Livewire/Admin/UserTable.php):
use Arm092\LivewireDatatables\DataTableComponent;
use App\Models\User;
class UserTable extends DataTableComponent
{
public function configure(): void
{
$this->setPrimaryKey('id');
$this->setModel(User::class);
$this->setSearch(true);
$this->setPerPage(10);
}
public function columns(): array
{
return [
'name' => 'Name',
'email' => 'Email',
'created_at' => 'Created At',
];
}
}
Blade Integration:
Render the table in your view (resources/views/livewire/admin/user-table.blade.php):
<div>
{!! $this->table(['showCheckboxes' => true]) !!}
</div>
Run Migrations/Seeders: Ensure your database is populated before testing.
create button linking to a form (e.g., route('users.create')).$emit to refresh the table post-create:
// In your create controller
return redirect()->route('users.index')->with('success', 'User created!');
public function mount(): void
{
$this->emit('alert', 'success', 'User created!');
}
setModel() to bind to Eloquent models or query builders:
$this->setModel(User::query()->where('active', true));
getData() for non-model data (e.g., API responses):
public function getData(): array
{
return $this->apiClient->fetchUsers();
}
public function columns(): array
{
return [
'id' => 'ID',
'name' => 'Name',
'email' => fn(User $user) => Str::of($user->email)->lower(),
];
}
'full_name' => fn(User $user) => "{$user->first_name} {$user->last_name}",
Html::button() or Html::link():
'actions' => fn(User $user) => Html::link(
route('users.edit', $user),
'Edit',
['class' => 'text-blue-500']
),
$this->setSearch(true);
Or add custom filters:
public function filters(): array
{
return [
'role' => ['x' => 'Admin', 'y' => 'User'],
'active' => ['x' => true, 'y' => false],
];
}
complexQueryBuilder for multi-condition filters:
public function complexQueryBuilder(): array
{
return [
'name' => 'Name',
'email' => 'Email',
'role' => 'Role',
];
}
$this->setShowCheckboxes(true);
$this->setActions([
'delete' => 'Delete',
'export' => 'Export',
]);
Handle actions in the component:
public function deleteSelected(): void
{
$this->selected()->each->delete();
$this->emit('alert', 'success', 'Items deleted!');
}
public function columns(): array
{
return [
'group:user_info' => [
'name' => 'Name',
'email' => 'Email',
],
'group:metadata' => [
'created_at' => 'Created At',
'updated_at' => 'Updated At',
],
];
}
$this->emit('refresh') or $this->refresh() after external changes (e.g., soft deletes).$this->emit('show-modal', ['id' => $user->id]);
resources/views/vendor/livewire-datatables/table.blade.php:
<table class="min-w-full divide-y divide-gray-200 {{ $classes ?? '' }}">
x-data="{ expanded: false }"
@click="expanded = !expanded"
:class="{ 'bg-gray-50': expanded }"
getData():
public function getData(): array
{
$response = Http::get('https://api.example.com/users');
return $response->json();
}
$component = new UserTable();
$component->setData(collect([new User()]));
$component->render();
$this->livewire(UserTable::class)
->setSearch('test')
->assertSee('test');
Performance with Large Datasets:
setPerPage(50) and implement server-side processing (override getData() to paginate API responses).Filter Persistence:
public function mount(): void
{
$this->filters = session('datatable_filters', []);
}
Column Sorting Conflicts:
'full_name' => [
'label' => 'Full Name',
'sortable' => true,
'accessor' => fn(User $user) => "{$user->first_name} {$user->last_name}",
],
Tailwind Conflicts:
'table' => [
'classes' => 'w-full',
'thead' => 'bg-gray-50',
],
Mass Action Race Conditions:
$ids = clone $this->selected()->pluck('id');
Log Queries:
Enable Laravel query logging in AppServiceProvider:
DB::enableQueryLog();
Dump queries in getData():
dd(DB::getQueryLog());
Inspect Component State:
Use dd($this->getData()) or dd($this->filters) to debug data binding.
Alpine.js Console:
Check browser console for Alpine errors (e.g., missing x-data bindings).
Livewire Hooks:
Override updated() to log changes:
public function updated($property): void
{
\Log::debug("Property '$property' updated to: " . $this->$property
How can I help you explore Laravel packages today?