Overview
Columns define which fields from your model are displayed in the table. All columns extend the base Column class and implement ColumnContract.
Defining Columns
Override the columns() method in your table component:
use Livewire\Tables\Columns\ TextColumn ;
use Livewire\Tables\Columns\ DateColumn ;
use Livewire\Tables\Columns\ BooleanColumn ;
public function columns () : array
{
return [
TextColumn :: make ( 'name' ) -> sortable () -> searchable (),
TextColumn :: make ( 'email' ) -> sortable () -> searchable (),
BooleanColumn :: make ( 'active' ) -> sortable (),
DateColumn :: make ( 'created_at' ) -> sortable (),
];
}
Column Types
TextColumn
Display plain text values:
TextColumn :: make ( 'name' )
-> label ( 'Product Name' )
-> sortable ()
-> searchable ();
Transform the displayed value:
TextColumn :: make ( 'price' )
-> label ( 'Price' )
-> sortable ()
-> format ( fn ( $value ) => '$' . number_format ( $value , 2 ));
Computed Columns
Create columns without a database field using render():
TextColumn :: make ()
-> label ( 'Full Name' )
-> render ( fn ( $row ) => $row -> first_name . ' ' . $row -> last_name );
When using make() with no arguments, you must provide a render() callback to define the cell content.
BooleanColumn
Display true/false values with visual indicators:
BooleanColumn :: make ( 'active' )
-> label ( 'Status' )
-> sortable ();
Renders a badge automatically:
True : Green badge
False : Red badge
Custom Labels
BooleanColumn :: make ( 'active' )
-> labels ( 'Active' , 'Inactive' );
Custom Rendering
BooleanColumn :: make ( 'verified' )
-> render ( fn ( $row ) => $row -> verified ? '✅' : '❌' );
BooleanColumn :: make ( 'active' )
-> format ( fn ( $value ) => $value ? 'Enabled' : 'Disabled' );
Priority order: render() > format() > default badge labels.
DateColumn
Display date values with customizable formatting:
DateColumn :: make ( 'created_at' )
-> label ( 'Created' )
-> sortable ()
-> format ( 'M d, Y' );
String Format
Closure Format
DateColumn :: make ( 'created_at' )
-> format ( 'Y-m-d' );
DateColumn :: make ( 'created_at' )
-> format ( 'd/m/Y H:i' );
Handles DateTimeInterface, strings, and null values automatically.
ImageColumn
Display images with lightbox preview:
ImageColumn :: make ( 'avatar_url' )
-> label ( 'Photo' )
-> alt ( 'name' )
-> dimensions ( 48 , 48 )
-> width ( '64px' );
Method Description alt(string $field)Model field used for the alt attribute dimensions(int $w, int $h)Image display dimensions width(string $css)Column CSS width (e.g., '200px')
Click to open a lightbox preview (Alpine.js x-teleport).
BladeColumn
Render custom Blade views or HTML:
BladeColumn :: make ()
-> label ( 'Status' )
-> render ( fn ( $row , $table ) => view ( 'tables.user-status' , [
'user' => $row ,
'table' => $table ,
]));
The closure receives:
$row — The Eloquent model for the current row
$table — The Livewire DataTableComponent instance
Searchable BladeColumn
Use a closure to define custom search logic:
BladeColumn :: make ()
-> label ( 'Full Name' )
-> searchable ( fn ( Builder $query , string $search ) => $query
-> orWhere ( 'first_name' , 'LIKE' , "%{ $search }%" )
-> orWhere ( 'last_name' , 'LIKE' , "%{ $search }%" )
)
-> render ( fn ( $row ) => $row -> first_name . ' ' . $row -> last_name );
ActionColumn
Row action buttons for edit, delete, or custom operations:
ActionColumn :: make ()
-> label ( 'Actions' )
-> button (
label : 'Edit' ,
action : fn ( $row ) => "editItem({ $row -> id })" ,
class : 'lt-btn-primary' ,
)
-> button (
label : 'Delete' ,
action : fn ( $row ) => "deleteItem({ $row -> id })" ,
class : 'lt-btn-primary' ,
visible : fn ( $row ) => $row -> can_delete ,
);
Parameter Type Description labelstringButton text actionClosureReturns the wire:click expression. Receives ($row, $table) classstringCSS classes for the button iconstring|nullOptional SVG/HTML icon prepended to label visibleClosure|boolPer-row visibility. Closure receives ($row)
Complete Example
public function columns () : array
{
return [
TextColumn :: make ( 'name' ) -> sortable () -> searchable (),
TextColumn :: make ( 'email' ) -> sortable (),
ActionColumn :: make ()
-> label ( 'Actions' )
-> button (
label : 'View' ,
action : fn ( $row ) => "viewUser({ $row -> id })" ,
class : 'lt-btn-primary' ,
icon : '<svg class="w-4 h-4">...</svg>' ,
)
-> button (
label : 'Delete' ,
action : fn ( $row ) => "confirmDelete({ $row -> id })" ,
class : 'lt-btn-primary' ,
visible : fn ( $row ) => auth () -> user () -> can ( 'delete' , $row ),
),
];
}
public function viewUser ( int $id ) : void
{
$this -> redirect ( route ( 'users.show' , $id ));
}
public function confirmDelete ( int $id ) : void
{
User :: findOrFail ( $id ) -> delete ();
}
Common Methods
All column types share these methods:
label()
Set the column header text:
TextColumn :: make ( 'name' ) -> label ( 'Full Name' );
sortable()
Enable sorting on this column:
TextColumn :: make ( 'name' ) -> sortable ();
Users can click the column header to sort. Multi-column sorting is supported by holding Shift.
searchable()
Include this column in global search:
TextColumn :: make ( 'name' ) -> searchable ();
Search on Specific Field
Useful for joined columns:
TextColumn :: make ( 'brand_name' )
-> label ( 'Brand' )
-> sortable ()
-> searchable ( 'brands.name' );
Custom Search Logic
For BladeColumn or complex search:
BladeColumn :: make ()
-> searchable ( fn ( Builder $query , string $search ) => $query
-> orWhere ( 'first_name' , 'LIKE' , "%{ $search }%" )
-> orWhere ( 'last_name' , 'LIKE' , "%{ $search }%" )
)
-> render ( fn ( $row ) => $row -> first_name . ' ' . $row -> last_name );
Transform the displayed value:
TextColumn :: make ( 'price' )
-> format ( fn ( $value ) => '$' . number_format ( $value , 2 ));
TextColumn :: make ( 'status' )
-> format ( fn ( $value , $row ) => strtoupper ( $value ));
render()
Compute cell content from the row model:
TextColumn :: make ()
-> label ( 'Total' )
-> render ( fn ( $row ) => $row -> quantity * $row -> unit_price );
render() takes precedence over format(). If both are set, format() is ignored.
hidden() / hideIf()
Hide columns by default:
TextColumn :: make ( 'internal_notes' ) -> hidden ();
TextColumn :: make ( 'admin_notes' ) -> hideIf ( ! auth () -> user () -> isAdmin ());
width()
Set column CSS width:
TextColumn :: make ( 'sku' ) -> width ( '120px' );
Styling Methods
TextColumn :: make ( 'price' )
-> headerClass ( 'text-right bg-green-50' )
-> cellClass ( 'text-right font-semibold' );
TextColumn :: make ( 'id' )
-> columnClass ( 'col-id' ); // Applied to both <th> and <td>
key()
Override the internal key:
TextColumn :: make ( 'name' ) -> key ( 'product_name' );
selectAs()
Override the resolution alias for joined columns:
TextColumn :: make ( 'brands.name' )
-> selectAs ( 'brand_name' )
-> sortable ();
view()
Use a custom Blade view for rendering:
TextColumn :: make ( 'status' ) -> view ( 'tables.status-badge' );
Factory Shorthands
Use the Column factory for cleaner syntax:
use Livewire\Tables\Columns\ Column ;
Column :: text ( 'name' );
Column :: boolean ( 'active' );
Column :: date ( 'created_at' );
Column :: image ( 'avatar' );
Column :: blade ();
Column :: actions ();
Joined Columns
For columns from joined tables, use dot notation:
public function query () : Builder
{
return Order :: query ()
-> join ( 'brands' , 'orders.brand_id' , '=' , 'brands.id' )
-> select (
'orders.*' ,
'brands.name as brands_name' ,
'brands.country as brands_country'
);
}
public function columns () : array
{
return [
TextColumn :: make ( 'orders.id' ) -> label ( '#' ) -> sortable (),
TextColumn :: make ( 'customer_name' ) -> sortable () -> searchable (),
TextColumn :: make ( 'brands.name' ) -> label ( 'Brand' ) -> sortable () -> searchable (),
TextColumn :: make ( 'brands.country' ) -> label ( 'Country' ) -> sortable (),
];
}
When using joins, always select table.* to avoid column conflicts. Use aliases for ambiguous columns.
Searching on Aliases
If you use an alias in the SELECT, specify the actual database column for search:
TextColumn :: make ( 'brand_name' )
-> label ( 'Brand' )
-> sortable ()
-> searchable ( 'brands.name' );
Complete Example
app/Livewire/ProductsTable.php
<? php
namespace App\Livewire ;
use App\Models\ Product ;
use Illuminate\Database\Eloquent\ Builder ;
use Livewire\Tables\Columns\ Column ;
use Livewire\Tables\Livewire\ DataTableComponent ;
class ProductsTable extends DataTableComponent
{
public function query () : Builder
{
return Product :: query ();
}
public function columns () : array
{
return [
Column :: image ( 'image_url' )
-> label ( 'Image' )
-> dimensions ( 80 , 80 )
-> alt ( 'name' ),
Column :: text ( 'name' )
-> label ( 'Product' )
-> sortable ()
-> searchable (),
Column :: text ( 'sku' )
-> label ( 'SKU' )
-> sortable ()
-> searchable (),
Column :: text ( 'price' )
-> label ( 'Price' )
-> sortable ()
-> headerClass ( 'text-right bg-green-50' )
-> cellClass ( 'text-right font-semibold' )
-> format ( fn ( $value ) => '$' . number_format ( $value , 2 )),
Column :: text ( 'stock' )
-> label ( 'Stock' )
-> sortable ()
-> headerClass ( 'text-right' )
-> cellClass ( 'text-right' ),
Column :: boolean ( 'active' )
-> label ( 'Status' )
-> sortable ()
-> labels ( 'Active' , 'Inactive' ),
Column :: date ( 'release_date' )
-> label ( 'Released' )
-> sortable ()
-> format ( 'M d, Y' ),
Column :: actions ()
-> button ( 'Edit' , fn ( $row ) => "edit({ $row -> id })" , 'lt-btn-primary' )
-> button ( 'Delete' , fn ( $row ) => "delete({ $row -> id })" , 'lt-btn-primary' ),
];
}
}
Next Steps
Filters Add filters to narrow down your data
Sorting & Search Configure search and multi-column sorting