Table
Patterns & Recipes
Ready-made column recipes — the cells applications keep rebuilding, written once.
User Table with Avatar
$table->columns([ StackedColumn::make('user') ->avatar('avatar_url') ->primary('name') ->secondary('email') ->circular() ->searchable() ->searchColumns(['name', 'email']), BadgeColumn::make('role') ->colors(['primary' => 'admin', 'success' => 'editor', 'gray' => 'viewer']), TextColumn::make('department.name') ->sortable() ->searchable(), TextColumn::make('posts.count') ->label('Posts') ->sortable() ->alignCenter(), TextColumn::make('last_login') ->since() ->sortable() ->textSize('sm') ->textColor('gray'), BooleanColumn::make('is_active'),]);
Financial Table
$table->columns([ TextColumn::make('number') ->searchable() ->fontFamily('mono'), TextColumn::make('client.name') ->searchable() ->sortable(), TextColumn::make('issued_at') ->date('d.m.Y') ->sortable(), TextColumn::make('due_at') ->date('d.m.Y'), TextColumn::make('total') ->money('CZK') ->sortable() ->alignRight() ->weight('bold') ->summarize('sum', 'Total'), BadgeColumn::make('status') ->colors([ 'draft' => 'gray', 'sent' => 'warning', 'paid' => 'success', 'overdue' => 'danger', ]), PollColumn::make('payment_status') ->intervalSeconds(30) ->badge() ->colors(['success' => 'received', 'warning' => 'pending', 'gray' => 'none']) ->pollWhile(fn ($state) => $state === 'pending'),]);
Task Board Table
$table->columns([ SelectColumn::make('status') ->options([ 'todo' => '📋 To Do', 'in_progress' => '🔄 In Progress', 'review' => '👀 Review', 'done' => '✅ Done', ]), TextColumn::make('title') ->searchable() ->weight('semibold') ->description(fn ($r) => Str::limit($r->body, 60)) ->actionUrl(fn ($r) => route('tasks.show', $r)), StackedColumn::make('assignee') ->avatar('assignee.avatar_url') ->primary('assignee.name') ->circular() ->avatarSize('sm'), BadgeColumn::make('priority') ->colors(['danger' => 'high', 'warning' => 'medium', 'gray' => 'low']) ->icons(['arrow-up' => 'high', 'minus' => 'medium', 'arrow-down' => 'low']), TextColumn::make('due_at') ->date('d.m.') ->textColor('gray') ->textSize('sm'),]);
A Column Class Of Your Own
When no fluent method on the shipped columns draws the cell you need, write a column class and its view:
php artisan make:wire-column Price
writes app/Tables/Columns/PriceColumn.php and
resources/views/tables/columns/price.blade.php. The class overrides
renderCell(), the one method a table calls for a cell, and hands the view
plain data — the table's fast render path sees the override and renders the
cell in full rather than splicing it into the text column's skeleton:
namespace App\Tables\Columns; use Illuminate\Database\Eloquent\Model;use NyonCode\WireTable\Columns\Column; class PriceColumn extends Column{ protected ?string $view = 'tables.columns.price'; public function renderCell(Model $record): string { if (! $this->canView() || ! $this->isVisibleForRecord($record)) { return ''; } $state = $this->getState($record); return trim($this->renderView('tables.columns.price', [ 'column' => $this, 'record' => $record, 'state' => $state, 'value' => $this->formatValue($state, $record), ])); } }
The view name is set on $view rather than only passed to renderView(), so
PriceColumn::make('price')->view('…') still overrides it for one table, and
the package's own tables.columns.* views are never looked up in its place.
value is the formatted state — the empty-cell text when there is none — so
->placeholder(), ->limit() and the rest keep working. An existing view is
never overwritten, --force replaces the class only, and
php artisan vendor:publish --tag=wire-table::stubs lets you change what it
writes.