Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Inertia Datatables Laravel Package

tooinfinity/inertia-datatables

Inertia DataTables for Laravel: server-side tables, filters, and sorting with an Inertia-friendly API. Zero stars, but a small, focused package for building fast data tables without leaving your Inertia stack.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a v0.0.1 pre-release, so treat the first hour as reconnaissance rather than integration. Skim the source before you write any app code — on a 0.0.1 the README will be thinner than the implementation, and the column/filter definition objects are where the real API lives.

Environment floor (hard):

  • PHP 8.4+
  • Laravel 12.x / 13.x (Testbench 10.x / 11.x if you test against it)
  • Inertia 3 + React 19 + TanStack Table v8 + shadcn/ui

If your app is on Laravel 11, PHP 8.3, React 18, or Inertia 2, stop now — this package cannot be retrofitted into that stack without upgrading the whole frontend. Verify which Inertia major you're actually running before composer require; the release notes pin to Inertia 3.

Install order:

  1. composer require the package, then publish the config (vendor:publish — confirm the tag from the service provider) so you can see the query parameter names before writing any frontend code.
  2. Add the shadcn registry component(s) — DataTable, Toolbar, Pagination, ColumnHeader, ColumnVisibility, Empty. These are copied into your repo, so commit them.
  3. Pull in the bundled TypeScript types and the useDataTable hook; check the hook's signature against the props your controller returns before wiring UI.

Where to look first: the config file (parameter names, defaults), then the column allow-list implementation, then useDataTable. Those three define the entire contract between backend and frontend.

First use case: a single simple index — e.g. a Users list with server-side pagination, global search over name/email, and one boolean filter (active). That exercises the full loop (query building → allow-list → Inertia prop → hook state → debounced partial reload) with no relation joins to muddy the debugging. Get that page working end-to-end before touching select filters or column search.

Implementation Patterns

Server owns the schema, client mirrors it. Define columns and filters in the controller/action, return the datatable payload as an Inertia prop, and keep the React column definitions purely presentational. The allow-list is the contract; the TS types are the mirror. When they drift you get silent no-ops (see Gotchas), so keep the two definitions physically adjacent in the repo.

Eloquent vs Query Builder:

  • Eloquent when you need global scopes, soft deletes, casts, or with() relations on the returned rows.
  • Query Builder when the source isn't a model or you need aggregates the package doesn't model. You lose scopes, so re-apply tenancy/soft-delete filters manually.
  • Relation search is not free — global search only reaches declared columns. For user.company.name you'll need an explicit join and a declared column alias, or a subquery select.

Partial reloads are the point. Drive every table interaction through Inertia visits with only: ['users'] (or whatever your prop is named) so search/sort/page changes don't re-render the layout or re-run unrelated page queries. This is what makes the debounced search feel cheap. If you find yourself doing router.reload() without only, you're leaving the package's main performance benefit on the table.

Filters: text/select/boolean cover most admin UIs. Validate the filter payload in a Form Request before it reaches the datatable — select filters especially, since an unvalidated value that happens to match a column name can broaden what the builder accepts. Treat the filter value as data, never as a column reference.

Frontend composition: useDataTable holds page/sort/search/filter state and debounces the search. Feed Toolbar the filter controls, ColumnHeader the sort affordances, and render ColumnVisibility/Empty/Pagination off the same state. Don't lift table state into a parent store — the hook assumes it owns the visit lifecycle.

Testing: Testbench makes this cheap. Write regression tests for the security boundary specifically: a request sorting on a non-allow-listed column must be rejected or ignored, and a filter with an unknown value must not alter the query. Those tests are what let you upgrade a 0.0.x package with any confidence.

Gotchas and Tips

  • No backward-compatibility promise. On v0.0.1 the prop shape, column definition object, and even the query parameter names can change between patches. Pin the exact version ("x.y.z", not ^), and treat every bump as a manual diff-and-review.
  • The allow-list is your only SQL-injection-adjacent boundary. Never forward a user-supplied sort/column/filter key into orderBy or whereColumn outside the package's resolution path. Confirm what the package does with a disallowed column — silently ignore vs. throw — and assert that behavior in a test. Silent ignoring hides typos; throwing is easier to debug. Know which you have.
  • Parameter naming is configurable, and that's a footgun. Rename once, early. The hook and the backend config must move together; a mismatch produces a table that renders and never filters, with no error.
  • count(*) is still a full scan. Server-side pagination runs a count query each request. With joins or large tables, add a covering index on your default sort column and watch for slow counts before you blame the package. Consider a keyset/simplePaginate path for very large datasets if the package exposes one.
  • Debounce + in-flight requests. Rapid typing produces overlapping requests. Verify the hook discards stale responses; if it doesn't, you'll see results flicker back to an older query. Reproduce with throttled network in devtools.
  • shadcn components are vendored, not imported. They live in your repo and will not update with the package. On upgrade, diff them manually — a package bump may expect a newer component variant than the one you copied at install time.
  • React 19 + shadcn + Inertia 3 peer ranges are the most likely install failure. If npm install resolves but the table silently fails to hydrate, check for a duplicated @tanstack/react-table or a second React copy in node_modules.
  • Debugging query behavior: log the resolved builder (or ->toSql() with bindings) immediately before execution. The generated SQL instantly tells you whether your sort column survived the allow-list, whether the filter applied, and whether a join caused duplicate rows.
  • Extension points to check in source: published config keys, per-column searchable/sortable flags, the base filter class (for a custom date-range or enum filter), and whether column definitions are a fluent builder or a plain array. On 0.0.1, extending an undocumented base class is the riskiest thing you can do — isolate any custom filter behind a thin wrapper so a breaking change is a one-file fix.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle