New version 1.30.0 is now available 🎉 Introducing a useful command to search for component usage.

Powerful suite of Blade components for TALL Stack apps.

Table

>= 1.6

Table component.

All examples in this page use Livewire through Laravel Volt because the TallStackUI documentation uses Livewire through Laravel Volt instead of pure Livewire components. You can use the table component in pure Livewire components, i.e. without Laravel Volt.

Although many packages can add table features to your project, starting from version 1.6.0 of TallStackUI you can take advantage of the simple table component, but with all the basic features necessary for a table to work through Livewire components.

You have two ways to provide data to create a table: 1) Simple data through an array or 2) Data that comes from the database, using Laravel Eloquent Pagination. The main difference between the two ways is that when choosing to create a table with an array of data, features such as filtering, sorting and pagination will be more difficult to implement.

1) Simple data through an array

@php
$headers = [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
// ...
];
 
$rows = [
['id' => 1, 'name' => 'Taylor Otwell'],
['id' => 2, 'name' => 'Nuno Maduro'],
// ...
];
@endphp
 
<x-table :$headers :$rows />

2) Data that comes from the database

<?php
 
use App\Models\User;
use Livewire\Volt\Component;
 
new class extends Component {
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::all(),
];
}
}; ?>
 
<div>
<x-table :$headers :$rows />
</div>
# Member Name
1 Taylor Otwell
2 Nuno Maduro
3 Dries Vints
4 Jess Archer
5 James Brooks
6 Mohamed Said
7 Tim MacDonald
8 Joe Dixon
9 Mior Muhammad Zaki Mior Khairuddin
10 Guus Leeuw
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
 
new class extends Component {
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::all(),
];
}
}; ?>
 
<div>
<x-table :$headers :$rows />
</div>
1 Taylor Otwell
2 Nuno Maduro
3 Dries Vints
4 Jess Archer
5 James Brooks
6 Mohamed Said
7 Tim MacDonald
8 Joe Dixon
9 Mior Muhammad Zaki Mior Khairuddin
10 Guus Leeuw
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
 
new class extends Component {
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::all(),
];
}
}; ?>
 
<div>
<x-table :$headers :$rows headerless />
</div>
# Member Name
1 Taylor Otwell
2 Nuno Maduro
3 Dries Vints
4 Jess Archer
5 James Brooks
6 Mohamed Said
7 Tim MacDonald
8 Joe Dixon
9 Mior Muhammad Zaki Mior Khairuddin
10 Guus Leeuw
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
 
new class extends Component {
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::all(),
];
}
}; ?>
 
<div>
<x-table :$headers :$rows striped />
</div>
# Member Name
1 Taylor Otwell
2 Nuno Maduro
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
use Illuminate\Database\Eloquent\Builder;
 
new class extends Component {
 
public ?int $quantity = 2;
 
public ?string $search = null;
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::query()
->when($this->search, function (Builder $query) {
return $query->where('name', 'like', "%{$this->search}%");
})
->paginate($this->quantity)
->withQueryString()
];
}
}; ?>
 
<div>
<x-table :$headers :$rows filter />
 
<!-- You can control the items of the quantity selector -->
<x-table :$headers
:$rows
filter
:quantity="[2,5,10]" />
 
<!-- You can specify different properties for the filter -->
<x-table :$headers
:$rows
:filter="['quantity' => 'foo', 'search' => 'bar']"
:quantity="[2,5,10]" />
 
<!-- You can disable one of the filters -->
<x-table :$headers
:$rows
:filter="['quantity' => 'quantity']"
:quantity="[2,5,10]" />
</div>

The search input bind the property using wire:model.live with debounce of 500ms.

An option to display a loading effect when interacts with the table elements.

# Member Name
1 Taylor Otwell
2 Nuno Maduro
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
use Illuminate\Database\Eloquent\Builder;
 
new class extends Component {
 
public ?int $quantity = 10;
 
public ?string $search = null;
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::query()
->when($this->search, function (Builder $query) {
return $query->where('name', 'like', "%{$this->search}%");
})
->paginate($this->quantity)
->withQueryString()
];
}
}; ?>
 
<div>
<x-table :$headers :$rows filter loading />
</div>

Sorting when clicking on the header names of the table.

# Member Name
11 Christoph Rumpel
10 Guus Leeuw
9 Mior Muhammad Zaki Mior Khairuddin
8 Joe Dixon
7 Tim MacDonald
6 Mohamed Said
5 James Brooks
4 Jess Archer
3 Dries Vints
2 Nuno Maduro
<?php
 
use App\Models\User;
use Livewire\Volt\Component;
 
new class extends Component {
 
public array $sort = [
'column' => 'id',
'direction' => 'desc',
];
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
// You can disable the sorting for specific columns
['index' => 'name', 'label' => 'Member', 'sortable' => false],
],
'rows' => User::query()
->orderBy(...array_values($this->sort))
->paginate(10)
->withQueryString()
];
}
}; ?>
 
<div>
<x-table :$headers :$rows :$sort />
</div>
# Member Name
1 Taylor Otwell
2 Nuno Maduro
<?php
 
use App\Models\User;
use Livewire\WithPagination;
use Livewire\Volt\Component;
 
new class extends Component {
use WithPagination;
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
],
'rows' => User::query()
->paginate(2)
->withQueryString()
];
}
}; ?>
 
<div>
<x-table :$headers :$rows paginate />
 
<!-- You can use the paginator with mobile style even when in desktop -->
<x-table :$headers :$rows paginate simple-pagination />
 
<!--
You can enable view persistence for the table by setting the `persistent`
and `id` parameters. The `id` parameter is necessary to avoid conflicts
when there is more than one table on the same page.
-->
<x-table :$headers :$rows paginate persistent id="users" />
 
<!--
You can disable the TallStackUI paginator element. When you do that
the table component will use the Livewire paginator element.
-->
<x-table :$headers :$rows paginate :paginator="null" />
</div>

Header Slot

# Member Name
1 Taylor Otwell
2 Nuno Maduro

Footer Slot

<!-- This is a resumed example without the full explanation -->
 
<x-table header="Header Slot"
footer="Footer Slot"
... />
 
<!-- Or -->
 
<x-table ...>
<x-slot:header>
Raw Header Slot
</x-slot:header>
<x-slot:footer>
Raw Footer Slot
</x-slot:footer>
</x-table>

The table component provides a custom Blade directive @interact to allow you to interact with the table columns about the data provided in each row. Allowing you to interact with the table and make things like add an action button for each row.

<?php
 
use App\Models\User;
use Livewire\WithPagination;
use Livewire\Volt\Component;
use Illuminate\Database\Eloquent\Builder;
 
new class extends Component {
use WithPagination;
 
public ?int $quantity = 10;
 
public ?string $search = null;
 
public function delete(string $id): void
{
dd($id);
}
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
['index' => 'action'],
],
'rows' => User::query()
->when($this->search, function (Builder $query) {
return $query->where('name', 'like', "%{$this->search}%");
})
->paginate($this->quantity)
->withQueryString(),
'type' => 'data',
];
}
}; ?>
 
<div>
<!-- 1: -->
<x-table :$headers :$rows filter paginate id="users">
<!-- The $row represents the instance of \App\Model\User of each row -->
@interact('column_action', $row)
<x-button.circle color="red"
icon="trash"
wire:click="delete('{{ $row->id }}')" />
@endinteract
</x-table>
 
<!-- 2: You can pass extra variables to the directive -->
<x-table :$headers :$rows filter paginate id="users">
@interact('column_action', $row, $type)
<x-button.circle color="red"
icon="trash"
wire:click="delete('{{ $row->id }}', '{{ $type }}')" />
@endinteract
</x-table>
</div>

As mentioned in the Livewire documentation, for cases where you want to render components in a loop, using the Blade @interact directive, you must specify a unique key for each component:

<?php
 
use App\Models\User;
use Livewire\WithPagination;
use Livewire\Volt\Component;
use Illuminate\Database\Eloquent\Builder;
 
new class extends Component {
use WithPagination;
 
public ?int $quantity = 10;
 
public ?string $search = null;
 
public function with(): array
{
return [
'headers' => [
['index' => 'id', 'label' => '#'],
['index' => 'name', 'label' => 'Member'],
['index' => 'action'],
],
'rows' => User::query()
->when($this->search, function (Builder $query) {
return $query->where('name', 'like', "%{$this->search}%");
})
->paginate($this->quantity)
->withQueryString(),
];
}
}; ?>
 
<div>
<x-table :$headers :$rows filter paginate id="users">
@interact('column_action', $row)
<livewire:delete.user :user="$row" :key="uniqid()" />
@endinteract
</x-table>
</div>

Code highlighting provided by Torchlight