raprmdn / laravel-inertia-datatables
Laravel server-side data table query builder with optional Inertia React components.
Package info
github.com/raprmdn/laravel-inertia-datatables
pkg:composer/raprmdn/laravel-inertia-datatables
Requires
- php: ^8.2
- illuminate/database: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/pagination: ^10.0|^11.0|^12.0|^13.0
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- nesbot/carbon: ^2.72|^3.0
This package is auto-updated.
Last update: 2026-06-26 08:19:19 UTC
README
This package is currently in beta. It is usable, but the public API may still change before
v1.0.0.
raprmdn/laravel-inertia-datatables is a Laravel server-side datatable query builder. The current core package is backend-only and can be used with Inertia, API resources, Blade, or any Laravel response.
Installation
composer require raprmdn/laravel-inertia-datatables
Publish Config
php artisan vendor:publish --tag=inertia-datatables-config
Published file:
config/inertia-datatables.php
Configuration
return [ 'query_params' => [ 'search' => 'search', 'filters' => 'filters', 'column' => 'col', 'direction' => 'sort', 'limit' => 'limit', ], 'date_format' => 'd-m-Y', 'pagination' => [ 'default_per_page' => 10, 'max_per_page' => 100, 'on_each_side' => 1, ], 'json_columns' => [], ];
query_params: request query keys used by search, filters, sorting, and pagination.date_format: expected incoming date range format.pagination: default page size, max page size, and paginator link window.json_columns: columns that should use JSON contains filtering.
Basic Usage
use App\Models\User; use Raprmdn\DataTables\Facades\DataTable; $users = DataTable::query(User::query()) ->searchable(['name', 'email']) ->orderBy('created_at', 'desc') ->make();
Query Parameters
Search
?search=raprmdn
->searchable(['name', 'email', 'contact.name'])
Filters
?filters[]=status:new&filters[]=priority:High
Filters use a mapping where:
- Key is the filter name received from the request.
- Value is the database column or relationship column.
$filterColumns = [ 'status' => 'status', 'priority' => 'priority.name', ]; [$columnFilters, $dateRanges] = DataTable::parseFilters( $request->query('filters', []), $filterColumns ); DataTable::query($query) ->applyFilters($columnFilters) ->allowedFilters(array_values($filterColumns)) ->make();
Special filter values: NULL, NOT NULL.
Date Range Filters
?filters[]=created_at_from:01-01-2026&filters[]=created_at_to:31-12-2026
Date range filter keys should end with _from and _to.
$filterColumns = [ 'status' => 'status', 'created_at_from' => 'created_at_from', 'created_at_to' => 'created_at_to', ]; [$columnFilters, $dateRanges] = DataTable::parseFilters( $request->query('filters', []), $filterColumns ); DataTable::query($query) ->applyFilters($columnFilters) ->allowedFilters(array_values($filterColumns)) ->applyDateRanges($dateRanges) ->make();
Date input format is controlled by inertia-datatables.date_format.
Sorting
?col=created_at&sort=desc
Sorting uses a mapping where:
- Key is the column name received from the request.
- Value is the database column or relationship column.
$sortColumns = [ 'name' => 'name', 'email' => 'email', 'created_at' => 'created_at', ]; [$sort, $allowedSorts] = DataTable::parseSort( $request->query('col'), $sortColumns ); DataTable::query($query) ->applySort($sort) ->allowedSorts($allowedSorts) ->orderBy('created_at', 'desc') ->make();
Only asc and desc directions are valid. Invalid sort columns fallback to the default order.
If the requested column is empty or not found in the mapping, $sort will be null and the DataTable will use the default orderBy() column.
Pagination
?limit=25
DataTable::query($query) ->perPage(25) ->make();
Use collection output when pagination is not needed:
DataTable::query($query) ->type('collection') ->make();
Relations
Searching, filtering, and sorting support relationship columns using dot notation.
'contact.name' 'priority.sla_minutes' 'reason.parent.name'
The first part is the relationship method defined on your Eloquent model, and the last part is the column on the related table.
For example:
'contact.name'
contact→contact()relationship defined in theTicketmodel.name→namecolumn in thecontactstable.
Nested relationships are also supported:
'reason.parent.name'
reason→ relationship onTicketparent→ relationship onReasonname→ column in the parent relation table.
Use Laravel relationship names for eager loading:
->with(['contact.channel', 'priority']) ->withCount(['tickets'])
Note: Relation sorting currently supports
BelongsToandHasOnerelationships. Sorting on ambiguous relationships such asHasManyorBelongsToManymay throw an exception.
Available Methods
query($query): set the Eloquent or query builder instance.with([...]): eager load relationships.withCount([...]): eager load relationship counts.searchable([...]): set searchable columns and relation columns.applyFilters([...]): apply parsed filters.allowedFilters([...]): whitelist filter columns.applyDateRanges([...]): apply parsed date ranges.applySort($column): set requested sort column. Acceptsnullto use default ordering.allowedSorts([...]): whitelist sort columns.DataTable::parseFilters($filters, $filterColumns): parse request filters into column filters and date ranges.DataTable::parseSort($column, $sortColumns): parse requested sort column and allowed sorts from one mapping.orderBy($column, $direction): set fallback order.perPage($limit): set default pagination limit.type('pagination'): return paginated results.type('collection'): return collection results.make(): execute the query.
Helper Methods
DataTable::parseFilters()
DataTable::parseFilters() converts request filters into:
$columnFilters— normal column or relationship filters forapplyFilters().$dateRanges— date range filters forapplyDateRanges().
It accepts 2 parameters:
DataTable::parseFilters( $request->query('filters', []), $filterColumns );
Example filter mapping:
$filterColumns = [ 'status' => 'status', 'channel' => 'contact.channel.name', 'created_at_from' => 'created_at_from', 'created_at_to' => 'created_at_to', ];
Example request:
?filters[]=status:closed
&filters[]=channel:Instagram
&filters[]=created_at_from:01-05-2026
&filters[]=created_at_to:30-06-2026
Usage:
[$columnFilters, $dateRanges] = DataTable::parseFilters( $request->query('filters', []), $filterColumns );
Result:
$columnFilters = [ 'status:closed', 'contact.channel.name:Instagram', ]; $dateRanges = [ 'created_at' => [ 'from' => '01-05-2026', 'to' => '30-06-2026', ], ];
Then pass the result to the DataTable:
DataTable::query($query) ->applyFilters($columnFilters) ->allowedFilters(array_values($filterColumns)) ->applyDateRanges($dateRanges) ->make();
DataTable::parseSort()
DataTable::parseSort() converts a request sort key into:
$sort— selected database or relationship column forapplySort().$allowedSorts— allowed sortable columns forallowedSorts().
It accepts 2 parameters:
DataTable::parseSort( $request->query('col'), $sortColumns );
Example sort mapping:
$sortColumns = [ 'ticket' => 'number', 'channel' => 'contact.channel.name', 'priority' => 'priority.sla_minutes', ];
Example request:
?col=channel&sort=asc
Usage:
[$sort, $allowedSorts] = DataTable::parseSort( $request->query('col'), $sortColumns );
Result:
$sort = 'contact.channel.name'; $allowedSorts = [ 'number', 'contact.channel.name', 'priority.sla_minutes', ];
Then pass the result to the DataTable:
DataTable::query($query) ->applySort($sort) ->allowedSorts($allowedSorts) ->make();
Example Inertia Controller
use App\Http\Resources\ContactResource; use App\Http\Resources\TicketResource; use App\Models\Contact; use App\Models\Ticket; use Illuminate\Http\Request; use Raprmdn\DataTables\Facades\DataTable; public function show(Request $request, Contact $contact) { $contact->load(['channel', 'createdBy']); $query = Ticket::query()->where('contact_id', $contact->id); $filterColumns = [ 'status' => 'status', 'priority' => 'priority.name', 'channel' => 'contact.channel.name', 'reason_type' => 'reason.parent.name', 'department' => 'department.name', 'assigned' => 'assignedTo.name', 'created_by' => 'creator.name', 'created_at_from' => 'created_at_from', 'created_at_to' => 'created_at_to', ]; [$columnFilters, $dateRanges] = DataTable::parseFilters( $request->query('filters', []), $filterColumns ); $sortColumns = [ 'ticket' => 'number', 'status' => 'status', 'priority' => 'priority.sla_minutes', 'channel' => 'contact.channel.name', 'customer' => 'contact.name', 'department' => 'department.name', 'assigned' => 'assignedTo.name', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'created_by' => 'creator.name', ]; [$sort, $allowedSorts] = DataTable::parseSort( $request->query('col'), $sortColumns ); $tickets = DataTable::query($query) ->with([ 'priority', 'assignedTo', 'contact.channel', 'department', 'reason.parent', 'reason', 'subReason', 'creator', 'updater', ]) ->searchable([ 'number', 'reason.name', 'reason.parent.name', 'subReason.name', 'contact.name', 'contact.email', 'contact.phone', ]) ->applySort($sort) ->allowedSorts($allowedSorts) ->applyFilters($columnFilters) ->allowedFilters(array_values($filterColumns)) ->applyDateRanges($dateRanges) ->make(); return inertia('contact/show', [ 'contact' => ContactResource::make($contact), 'tickets' => TicketResource::collection($tickets), ]); }
API Example
use App\Http\Resources\UserResource; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Raprmdn\DataTables\Facades\DataTable; Route::get('/users', function (Request $request) { $sortColumns = [ 'name' => 'name', 'email' => 'email', 'created_at' => 'created_at', ]; [$sort, $allowedSorts] = DataTable::parseSort( $request->query('col'), $sortColumns ); $users = DataTable::query(User::query()) ->searchable(['name', 'email']) ->applySort($sort) ->allowedSorts($allowedSorts) ->make(); return UserResource::collection($users); });
Inertia React Components
This package currently focuses on the Laravel backend query builder.
Publishable Inertia React starter components are planned for a future release. Until that release, you can use this package with your own Inertia, React, Vue, Blade, or API frontend.
Known Limitations
- Beta release, API may change.
- Inertia React components are planned but not part of the current beta release.
- String column and relation names inside arrays may not get perfect IDE autocomplete.
- Relation sorting does not support every relation type.
- Advanced filter operators are not implemented yet.
Roadmap
- Tests
- Better documentation
- More filter operators
- Optional Inertia React starter components
- Column definitions API
Contributing
Issues and pull requests are welcome while the package is in beta. Keep changes focused and backend-first unless the change is explicitly about planned frontend starter components.
License
This package is open-sourced software licensed under the MIT license.