Your first table
After installation, three steps add a users page. Two optional changes
then show more of what a table can do. The example uses Laravel’s React starter kit, its User
model and an account you can sign in with; in another app, keep your own page names and layout.
1. Define the table
Section titled “1. Define the table”Laravel
<?php
namespace App\Http\Controllers;
use App\Models\User;use Inertia\Inertia;use Inertia\Response;use InertiaX\Table\Columns\NumberColumn;use InertiaX\Table\Columns\TextColumn;use InertiaX\Table\Table;
class UserController{ public function index(): Response { return Inertia::render('users/index', [ Table::make('users') ->data(User::class) ->addColumns([ NumberColumn::make('id')->numberCast('int')->visible(false), TextColumn::make('name')->searchable()->sortable(), TextColumn::make('email'), ]), ]); }}The id column identifies each row; visible(false) hides it.
2. Render the table
Section titled “2. Render the table”Create the page for users/index. The starter kit’s layout wraps it, and the highlighted lines are
the InertiaX part:
React
import { Head } from '@inertiajs/react';import { AppTable } from '@/components/app-table';
export default function UsersIndex() { return ( <> <Head title="Users" /> <section className="m-4 rounded-xl border p-6"> <h1 className="text-lg font-semibold">Users</h1> <p className="mb-4 text-sm text-muted-foreground"> Everyone who can sign in. </p> <AppTable prop="users" /> </section> </> );}3. Add the route
Section titled “3. Add the route”Add it to the starter kit’s group for signed-in users:
Laravel
use App\Http\Controllers\UserController;
Route::middleware(['auth', 'verified'])->group(function () { // ... Route::get('users', [UserController::class, 'index'])->name('users.index');});See it work
Section titled “See it work”That’s the whole table. A new app may have only your own account, so add some users first:
php artisan tinker --execute="App\Models\User::factory(30)->create()"Sign in and open /users: their names and email addresses appear in a styled table. Search for
part of a name, click the Name heading to sort, and page through the rows.
Try more (optional)
Section titled “Try more (optional)”Each change below edits only UserController; the React page stays as it is.
Add a filter
Section titled “Add a filter”Make the email column filterable:
Laravel
->addColumns([ NumberColumn::make('id')->numberCast('int')->visible(false), TextColumn::make('name')->searchable()->sortable(), TextColumn::make('email')->filterable(),]),Automatic filters are on by default, so a filterable column gets a filter with comparisons for its
type. Reload /users and click the new Filter button: choose Email, change Equals to
Ends With, enter example.org and click Add filter. The rows narrow to those addresses,
and the filter stays in the URL, so a reload or a shared link keeps it.
Or let InertiaX infer the columns and filters
Section titled “Or let InertiaX infer the columns and filters”In UserController, replace the return statement in index() with this one, which infers the
columns from the User model; the NumberColumn and TextColumn imports are then unused. Inferred
columns aren’t searchable, sortable or filterable until the table turns that on:
Laravel
return Inertia::render('users/index', [ Table::make('users') ->data(User::class) ->autoColumns() ->searchableColumns() ->sortableColumns() ->filterableColumns(),]);Reload /users. If you searched or filtered earlier, the URL keeps it: clear the search box and
click Clear filters to see every user. The table now shows every field the model serializes,
such as Email Verified At and Created At, without $hidden fields such as the password.
Text columns are searchable, and every column you see sorts and has a filter for its type.
A column that can be null also gets Is empty. The factory users are all verified, so add one that isn’t:
php artisan tinker --execute="App\Models\User::factory()->unverified()->create()"Then filter Email Verified At by Is empty to find it.
Inference shows whatever the model serializes, so review those fields before you ship the page; see Choose fields deliberately. To leave a field out or customize one, see Infer columns from a model.
Next steps
Section titled “Next steps”Choose what your page needs next:
- Show a related record’s field, such as an order’s customer name, or count related rows: Show a related field.
- Use the same table on another page: Reuse a table class.
- Link a cell to its record: Link to a record.
- Show the rows as cards: Custom layouts.
- Change colors and spacing: Styling.
In production, pass a query scoped to your application’s authorization and access rules. See Authorization & security.