fsi/datagrid
FSI DataGrid is a Laravel package for building configurable data grids. Define columns, filters, sorting, pagination and row actions in PHP, then render sortable, searchable tables with minimal code.
Treat fsi/datagrid as a standalone PHP presentation component, not a Laravel package. It has no Laravel service provider, facade, Blade directives, config file, or auto-discovery. You are wiring it into Laravel yourself.
Version 2.1.0 makes this materially more viable on a modern Laravel stack than earlier releases: it allows PHP 8, drops doctrine/persistence below 1.3, and drops Symfony 2.x components in favor of some Symfony 5.x components. That maps roughly onto Laravel 8/9-era dependency graphs. It is still not Laravel-native, and there is no indication of testing beyond the PHP 8.0/8.1 window.
Minimal path:
Install and inspect:
composer require fsi/datagrid
Look first at:
README.md and CHANGELOG.mdcomposer.json (check the exact php, symfony/*, and doctrine/persistence constraints)src/DataGridFactoryBuilder.php / src/DataGridFactory.phpsrc/Column/src/DataSource/Bind the factory once in a service provider:
use FSi\Component\DataGrid\DataGridFactory;
use FSi\Component\DataGrid\DataGridFactoryBuilder;
public function register(): void
{
$this->app->singleton(DataGridFactory::class, function () {
return DataGridFactoryBuilder::build();
});
}
First useful use case: a read-only admin listing from an array or already-loaded Eloquent collection.
$grid = $factory->createDataGrid('users');
$grid->addColumn('id', 'number', ['label' => 'ID']);
$grid->addColumn('name', 'text', ['label' => 'Name']);
$grid->addColumn('email', 'text', ['label' => 'Email']);
$grid->addColumn('created_at', 'datetime', ['label' => 'Created']);
$grid->setData(new ArrayDataSource(
User::query()->latest()->limit(50)->get()->toArray()
));
$view = $grid->createView();
return view('admin.users.index', ['grid' => $view]);
Render manually in Blade. There is no package-provided Laravel table renderer; iterate the view’s columns and rows and escape output with Blade {{ }}.
Use this package only if you need its column-object abstraction. For a new Laravel CRUD screen, a simple Blade table or a maintained Laravel table package is usually less work.
Keep one grid definition class per listing.
Put grid configuration in app/DataGrids/UserGrid.php or similar. Inject the shared DataGridFactory, build columns there, and return the view. This keeps controllers small and makes column changes reviewable.
final class UserGrid
{
public function __construct(private DataGridFactory $factory) {}
public function view(Collection $users): mixed
{
$grid = $this->factory->createDataGrid('users');
$grid->addColumn('id', 'number', ['label' => 'ID']);
$grid->addColumn('name', 'text', ['label' => 'Name']);
$grid->addColumn('email', 'text', ['label' => 'Email']);
$grid->setData(new ArrayDataSource($users->toArray()));
return $grid->createView();
}
}
Adapt Eloquent through a data source boundary.
The package expects a data source, not an Eloquent builder. The simplest reliable pattern is to paginate/filter/sort in Laravel first, then pass the resulting rows as arrays to ArrayDataSource. For larger datasets, write a custom data source implementing the package’s DataSourceInterface and normalize models into the row shape your columns expect.
Do query concerns outside the grid.
Treat fsi/datagrid as a renderer, not a query layer. Handle:
orderBy() based on validated request parameterswith() to avoid N+1 queriesPass only the page of rows the grid should display.
Render through a Blade partial.
Create resources/views/admin/partials/datagrid.blade.php and render labels and row values yourself. Keep escaping on:
<table>
<thead>
<tr>
@foreach ($grid->getColumns() as $column)
<th>{{ $column->getLabel() }}</th>
@endforeach
</tr>
</thead>
<tbody>
@foreach ($grid->getRows() as $row)
<tr>
{{-- use the row/column API exposed by the installed version --}}
</tr>
@endforeach
</tbody>
</table>
Confirm the exact view API (getColumns(), getRows(), row cell access) in the package source; it is old enough that examples online may not match your installed version — and 2.1.0 is a dependency-constraint release, not an API release, so the view layer is unchanged.
Use custom column types sparingly.
If a value needs special formatting, first try transforming the row before handing it to the grid. If you need reusable behavior across grids, register a custom column type with the factory builder/extensions during application boot. Keep custom types small and test them with ArrayDataSource.
Use ArrayDataSource for tests.
This is the easiest way to lock down column definitions and rendering behavior without a database. Assert that the grid view contains expected labels and row values.
Convert the view for APIs or Inertia if needed.
If you are not rendering HTML, iterate the grid view and map it into a plain array in a presenter or resource class. Do not leak the package’s view object into your public API response shape.
doctrine/persistence < 1.3, and drops Symfony 2.x while allowing "some" Symfony 5.x components. No new rendering API, no Laravel hooks, no deprecations to migrate. Plan for no functional change after upgrading.composer.json. Symfony 5.x components were never validated against PHP 8.3+, and this package has no CI signal for it. Smoke-test on your target runtime before adopting, and be prepared to pin if static analysis or runtime deprecations surface.doctrine/persistence >= 1.3 and specific Symfony 5.x components can conflict with what your Laravel version already pulls in, or with packages still on Doctrine 2/Symfony 6. If Composer resolution is painful, that is a strong signal not to force it into the application.{!! !!} unless you have sanitized them. Use Blade escaping for user-controlled data.text, number, datetime, and other type names in src/Column/ for the installed version. Old blog examples may target different FSi versions.ArrayDataSource first. If a grid is blank or misaligned, replace the real data source with a small array and dump the created view. That isolates column configuration from query/data-source issues.How can I help you explore Laravel packages today?