Skip to content

Recipes

These recipes build on Your first Table. Each keeps source behavior in Laravel and presentation behavior in React.

Start from the inferred Table in the quick start and explicitly add only the fields whose presentation is part of your domain. Bulk inference skips those existing keys:

InertiaX::table('users')
->data(User::class)
->autoColumns()
->filterableColumns()
->autoFilters()
->addColumn(
TextColumn::make('name', 'Full name')
->searchable()
->sortable()
->filterable(),
)
->addColumn(
TextColumn::make('email', 'Email address')
->searchable()
->filterable()
->copyable(),
);

This preserves automatic inference for the remaining allowed model fields. Move to a fully explicit columns() declaration when the whole Table becomes intentional application UI.

InertiaX::table('users')
->data(User::query()->whereBelongsTo($account))
->addColumns([
NumberColumn::make('id', 'ID')->sortable(),
TextColumn::make('name', 'Name')->sortable()->searchable(),
TextColumn::make('email', 'Email')->searchable(),
BadgeColumn::make('status', 'Status'),
])
->pageSize(25)
->pageSizeOptions([10, 25, 50]);

Only the marked Columns participate in search and sorting. Tenant scoping remains part of the base query.

AuditEventsTable::make('audit_events')
->data(collect($events))
->rowKey('event_id')
->pageSize(20);

Use this for an already-bounded domain result. For a large database dataset, pass an Eloquent builder so pagination and comparisons stay in SQL.

BadgeColumn::make('status', 'Status')
->variant([
'active' => 'success',
'invited' => 'secondary',
'blocked' => 'destructive',
])
->filterable()
->filter(
SelectFilter::make('status', 'Status')->options([
'active' => 'Active',
'invited' => 'Invited',
'blocked' => 'Blocked',
]),
);

The stored values remain stable while the cell and filter expose user-facing presentation.

use InertiaX\Components\Table\Enums\SelectionMode;
UsersTable::make('users')
->selection()
->selectionMode(SelectionMode::Single);
<InertiaX
prop="users"
table={{
events: {
selectionChange({ selection }) {
setSelectedUserId(selection[0]);
},
},
}}
/>

The event reports row IDs. Fetch or authorize any domain operation independently on the server.

return Inertia::render('Dashboard', [
ActiveUsersTable::make('active_users')->data(User::query()->where('active', true)),
AuditEventsTable::make('audit_events')->data($auditEvents),
]);
<>
<section>
<h2>Active users</h2>
<InertiaX prop="active_users" />
</section>
<section>
<h2>Audit events</h2>
<InertiaX prop="audit_events" />
</section>
</>

The application-level provider from Installation already owns both Tables. Distinct IDs isolate URL keys, partial reloads, and request ordering.

ActiveUsersTable::make('users')
->data(User::query()->where('active', true))
->addColumn(TextColumn::make('email', 'Email')->copyable())
->replaceColumn(BadgeColumn::make('role', 'Access level'))
->pageSize(50);

The base class stays reusable; the caller makes its difference explicit.

protected function columns(): array
{
return [
TextColumn::make('name', 'Name')->searchable(),
AutoColumn::make('score', 'Score')->sortable(),
DateTimeColumn::make('last_seen_at', 'Last seen')->sortable(),
];
}

AutoColumn infers the named Eloquent field while preserving the capabilities chained onto it.

function EmptyUsers({ colSpan }: TableStateRegionProps) {
return (
<tr>
<td colSpan={colSpan} className="py-12 text-center">
No users match these filters.
</td>
</tr>
);
}
<InertiaX prop="users" table={{ regions: { emptyState: EmptyUsers } }} />

This replaces only the empty row. Search, filters, requests, pagination, and the rest of the built-in renderer remain intact.

The canonical repository keeps three examples with deliberately different roles:

  • The Laravel workbench covers inline data, Eloquent, Collections, reusable classes, all built-in types, custom full-stack leaf types, multiple Tables, and real Inertia request round trips. It is the compatibility evidence.
  • The interactive demo source has User inference, explicit Order definitions, and a Collection activity feed as the stable #/users, #/orders, and #/audit screens. It executes deterministic browser fixtures and says so prominently; it is not Laravel, Eloquent, database, or Inertia evidence.
  • The React renderer lab is an internal conformance surface for direct envelopes, renderer customization, registered custom cells, and diagnosed fallback—not a customer demo.