The table component provides lifecycle hooks and Livewire event dispatch for integration with other components and external systems.
Lifecycle Hooks
Override these methods to hook into the table’s render cycle:
Method When Called Receives Returns onQuerying(Builder $query)Before pipeline processing Raw Eloquent builder void onQueried(LengthAwarePaginator $rows)After pipeline processing Paginated results void onRendering(array $viewData)Before view render View data array Modified array onRendered()After view render Nothing void
Example: Modify Query Before Processing
Add tenant scoping or other query modifications:
protected function onQuerying ( Builder $query ) : void
{
$query -> where ( 'tenant_id' , auth () -> user () -> tenant_id );
}
Example: Log Results
Track how many results are returned:
protected function onQueried ( LengthAwarePaginator $rows ) : void
{
logger () -> info ( "Table rendered with { $rows -> total ()} results" );
}
Pass additional data to the view:
protected function onRendering ( array $viewData ) : array
{
$viewData [ 'summary' ] = $this -> calculateSummary ( $viewData [ 'rows' ]);
return $viewData ;
}
onRendering() must return the modified $viewData array.
Measure query and render time:
private float $startTime ;
protected function onQuerying ( Builder $query ) : void
{
$this -> startTime = microtime ( true );
}
protected function onRendered () : void
{
$elapsed = microtime ( true ) - $this -> startTime ;
logger () -> debug ( "Table render took { $elapsed }s" );
}
Livewire Event Dispatch
Enable automatic Livewire event dispatch for the table lifecycle:
protected function shouldDispatchTableEvents () : bool
{
return true ;
}
This dispatches Livewire events that other components can listen to:
Event Dispatched table-queryingBefore pipeline table-queriedAfter pipeline table-renderingBefore view render table-renderedAfter view render
Listen From Another Component
use Livewire Attributes On ;
class DashboardStats extends Component
{
#[ On ( 'table-queried' )]
public function handleTableQueried () : void
{
// React to table data changes
$this -> refreshStats ();
}
}
External Refresh Events
Every table automatically listens for refresh events:
Event Scope Description livewire-tables-refreshGlobal Refreshes all tables on the page {tableKey}-refreshTargeted Refreshes a specific table
Global Refresh
Refresh all tables from any Livewire component:
$this -> dispatch ( 'livewire-tables-refresh' );
Targeted Refresh
Refresh a specific table using its tableKey:
class UserTable extends DataTableComponent
{
public string $tableKey = 'users' ;
}
// From another component:
$this -> dispatch ( 'users-refresh' );
From Alpine.js
Dispatch refresh events from Alpine components:
< button @click ="$dispatch('users-refresh')" >
Refresh Users
</ button >
Custom Event Name
Override the default refresh event name:
class UserTable extends DataTableComponent
{
protected string $refreshEvent = 'reload-user-data' ;
}
Now the table listens for reload-user-data instead of {tableKey}-refresh.
refreshTable() resets pagination to page 1 and triggers a re-render. Search, filters, and sorting are preserved.
Custom Listeners
Add custom event listeners to your table:
public function listeners () : array
{
return [
'user-created' => 'refreshTable' ,
'order-updated' => 'handleOrderUpdate' ,
];
}
public function handleOrderUpdate () : void
{
$this -> resetPage ();
}
Custom listeners are merged with the built-in refresh listeners.
Filter Events
Every table automatically dispatches a table-filters-applied event whenever filters or search change:
Event Payload
Parameter Type Description tableKeystringThe $tableKey of the table that changed filtersarrayAssociative array of currently active filters searchstringThe current search term
Empty or null filter values are omitted from the filters array.
Filter Value Types
Filter Type Example Value Text 'John'Select 'active'Select (multi) ['pending', 'shipped']Number '50'NumberRange ['min' => '100', 'max' => '500']Date '2024-01-15'DateRange ['from' => '2024-01-01', 'to' => '2024-12-31']MultiDate ['2024-01-01', '2024-06-15']Boolean '1' or '0'
When the Event Is Dispatched
The event fires in these methods:
applyFilter() — when a filter value is set or changed
removeFilter() — when a specific filter is removed
clearFilters() — when all filters are cleared
updatedSearch() — when the search input changes
clearSearch() — when the search is cleared
updatedTableFilters() — when wire:model bound filters change
Listening From a Parent Component
Update statistics or dependent UI based on filter changes:
use Livewire Attributes On ;
use Livewire Component ;
class DashboardPage extends Component
{
public array $activeFilters = [];
public array $searchTerms = [];
#[ On ( 'table-filters-applied' )]
public function onFiltersApplied ( string $tableKey , array $filters , string $search = '' ) : void
{
$this -> activeFilters [ $tableKey ] = $filters ;
$this -> searchTerms [ $tableKey ] = $search ;
}
public function render ()
{
$query = Order :: query ();
$filters = $this -> activeFilters [ 'orders' ] ?? [];
$search = $this -> searchTerms [ 'orders' ] ?? '' ;
if ( $search !== '' ) {
$query -> where ( function ( $q ) use ( $search ) {
$q -> where ( 'customer_name' , 'LIKE' , "%{ $search }%" )
-> orWhere ( 'product_name' , 'LIKE' , "%{ $search }%" );
});
}
if ( ! empty ( $filters [ 'status' ])) {
$query -> where ( 'status' , $filters [ 'status' ]);
}
if ( ! empty ( $filters [ 'unit_price' ])) {
if (( $filters [ 'unit_price' ][ 'min' ] ?? '' ) !== '' ) {
$query -> where ( 'unit_price' , '>=' , ( float ) $filters [ 'unit_price' ][ 'min' ]);
}
if (( $filters [ 'unit_price' ][ 'max' ] ?? '' ) !== '' ) {
$query -> where ( 'unit_price' , '<=' , ( float ) $filters [ 'unit_price' ][ 'max' ]);
}
}
return view ( 'livewire.dashboard' , [
'totalOrders' => $query -> count (),
'deliveredOrders' => ( clone $query ) -> where ( 'status' , 'delivered' ) -> count (),
'revenue' => ( clone $query ) -> sum ( 'total' ) ?? 0 ,
]);
}
}
Listening From Alpine.js
React to filter changes in Alpine components:
< div x-data = "{ filterCount: 0 }"
@table -filters-applied.window = "filterCount = Object.keys($event.detail.filters ?? {}).length" >
< span x-text = "filterCount + ' filters active'" ></ span >
</ div >
Multiple Tables
When you have multiple tables on the same page, use the tableKey to distinguish which table changed:
#[ On ( 'table-filters-applied' )]
public function onFiltersApplied ( string $tableKey , array $filters , string $search = '' ) : void
{
$this -> activeFilters [ $tableKey ] = $filters ;
$this -> searchTerms [ $tableKey ] = $search ;
}
public function render ()
{
// Products table stats
$productsQuery = Product :: query ();
foreach ( $this -> activeFilters [ 'products' ] ?? [] as $key => $value ) {
// Apply each filter...
}
// Orders table stats
$ordersQuery = Order :: query ();
foreach ( $this -> activeFilters [ 'orders' ] ?? [] as $key => $value ) {
// Apply each filter...
}
return view ( 'livewire.page' , [
'totalProducts' => $productsQuery -> count (),
'totalOrders' => $ordersQuery -> count (),
]);
}
Complete Example: Stats Cards
Stats cards that update automatically when filters change:
Table Component
Parent Component
Blade Template
class UserTable extends DataTableComponent
{
public string $tableKey = 'users' ;
public function filters () : array
{
return [
Filter :: make ( 'department' )
-> select ([
'engineering' => 'Engineering' ,
'sales' => 'Sales' ,
'marketing' => 'Marketing' ,
]),
Filter :: make ( 'status' )
-> select ([
'active' => 'Active' ,
'inactive' => 'Inactive' ,
]),
Filter :: make ( 'salary' )
-> numberRange ()
-> config ([ 'min' => 0 , 'max' => 200000 ]),
];
}
}
When filters change, the stats cards instantly update to reflect only the filtered dataset.