beartropy/tables
Flexible Livewire table component for the TALL stack (Tailwind, Alpine, Laravel, Livewire). Provides essentials like searching, sorting, filters, bulk actions, and column toggling to build customizable data tables quickly.
Installation:
composer require beartropy/tables
Publish assets (if needed):
php artisan vendor:publish --provider="Beartropy\Tables\BeartropyTableServiceProvider"
Generate a new table:
php artisan make:btable UserTable
This creates a Livewire component (app/Http/Livewire/UserTable.php) extending BeartropyTable.
Define columns in your table class:
public function columns()
{
return [
Column::make('name', 'Name')
->sortable()
->searchable(),
Column::make('email', 'Email')
->sortable(),
];
}
Use the table in Blade:
@livewire('user-table')
// app/Http/Livewire/UserTable.php
public function data()
{
return User::query();
}
public function columns()
{
return [
Column::make('id', 'ID'),
Column::make('name', 'Name')->sortable(),
Column::make('email', 'Email')->searchable(),
];
}
Data Source:
public function data()
{
return $this->model->query()
->when($this->search, fn($q) => $q->where('name', 'like', "%{$this->search}%"));
}
Column Configuration:
public function columns()
{
return [
Column::make('id', 'ID')->sortable(),
Column::make('name', 'Name')
->sortable()
->searchable()
->centered(),
Column::make('created_at', 'Created At')
->date()
->sortable(),
];
}
Bulk Actions:
public function bulkActions()
{
return [
BulkAction::make('delete')
->label('Delete Selected')
->icon('trash')
->action(fn($rows) => $this->deleteSelected($rows)),
];
}
protected function deleteSelected($rows)
{
foreach ($rows as $row) {
$this->model->find($row['id'])->delete();
}
$this->resetTable();
}
With Inertia/Laravel Boost:
public function mount()
{
$this->setComponentSize('md'); // Adjusts header button sizes
}
Custom Query Scoping:
public function query()
{
return parent::query()->where('active', true);
}
Dynamic Column Toggling:
public function toggleableColumns()
{
return ['email', 'phone']; // Columns users can hide/show
}
Export Integration:
public function export()
{
return GenericExport::make()
->columns($this->columns())
->from($this->data());
}
// Persist table state (search, sort, filters) between requests
protected $persistTableState = true;
// Cache data for 5 minutes
protected $cacheFor = 5;
Column Key Mismatch:
Column::make('key', 'Label') uses the exact same key as your data source.->key('custom_key') if your data uses non-standard keys.Livewire Serialization:
->serializable() or simplify data structure.Pagination Conflicts:
data() methods must return paginated results.->paginate() or use ->withQueryString().Bulk Action IDs:
->selectable() to columns and verify $this->selected contains IDs.Check Table State:
dd($this->getTableState());
Inspect Data:
dd($this->data()->get());
Column Modifiers:
->debug() to see all applied modifiers:Column::make('name')->debug();
Eager Loading:
public function query()
{
return parent::query()->with(['relationship']);
}
Disable Persistence:
protected $persistTableState = false;
Cache Invalidation:
$this->resetTable(); // Clears cache and state
Custom Column Types:
Column::make('status')
->badge()
->options([
'active' => 'Active',
'inactive' => 'Inactive',
]);
Override Views:
php artisan vendor:publish --tag=beartropy-tables-views
resources/views/vendor/beartropy-tables/...Custom Theming:
public function mount()
{
$this->setTheme('dark');
$this->setButtonThemeOverride('primary');
}
Secondary Headers:
Column::make('price')
->secondaryHeader(fn($rows) => 'Total: ' . $rows->sum('price'))
->currency();
Conditional Columns:
public function columns()
{
$columns = [
Column::make('name'),
];
if (auth()->can('view_emails')) {
$columns[] = Column::make('email');
}
return $columns;
}
Dynamic Data Sources:
public function data()
{
return $this->request->has('filter')
? $this->filteredData()
: $this->defaultData();
}
Row Expansion:
public function columns()
{
return [
Column::make('name')
->expandable()
->expandedView('livewire.user-detail', ['user' => fn($row) => $row]),
];
}
Virtual Columns:
Column::make('full_name')
->virtual()
->label('Full Name')
->get(function($row) {
return "{$row['first_name']} {$row['last_name']}";
});
How can I help you explore Laravel packages today?