laravel-inertia-datatables maintained by raprmdn
Laravel Inertia Datatables
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.