shwaeki / laravel-dynamictable
Laravel DynamicTable — a fast, zero-configuration data grid for Laravel. Maximum functionality with minimum configuration.
Requires
- php: ^8.2
- illuminate/contracts: ^10.0|^11.0|^12.0|^13.0
- illuminate/database: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- illuminate/view: ^10.0|^11.0|^12.0|^13.0
- symfony/finder: ^6.2|^7.0|^8.0
Requires (Dev)
- larastan/larastan: ^2.9|^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- pestphp/pest: ^2.0|^3.0|^4.0
Suggests
- livewire/livewire: Optional adapter to embed DynamicTable inside a Livewire component (^3.0|^4.0).
- maatwebsite/excel: Required for the xlsx Excel export/import adapter (^3.1|^4.0).
- openspout/openspout: Lightweight streaming alternative for very large exports (^4.0).
README
Maximum functionality with minimum configuration.
A fast, zero-configuration data grid for Laravel. Point it at a model and you get columns, search, filters, sorting, pagination, relationships, saved views, export, import and inline editing — server-side, secure, and without an N+1 in sight.
class UsersTable extends DynamicTable { protected string $model = User::class; }
@dynamicTable(UsersTable::class)
That's it. No Column::make() chain per field. No Livewire tag. No custom Blade
component. No route-as-table. No build step.
![]() |
![]() |
| Nested AND/OR filters | Add any column, including through relations |
![]() |
![]() |
| Dynamics-style column menu | Saved views, shared per user |
Install
composer require shwaeki/laravel-dynamictable
Nothing to publish. Nothing to build. Run php artisan migrate only if you want
saved views.
php artisan make:dynamic-table UsersTable
What you get for free
Point it at a model and DynamicTable reads the schema, the casts and the relationships, then makes sensible decisions:
department_idbecomes the department's name — eager loaded, one extra query for the whole page, never one per row- Booleans render as checks, enums as badges with their cases as filter options, dates in the current locale, decimals right-aligned
password,remember_tokenand anything token-shaped are never exposed- Server-side search, sorting and pagination
- The advanced filter builder, with grouped AND/OR conditions
- RTL when the locale is Arabic or Hebrew
Turn on what you need
Expensive things are opt-in. A disabled feature renders no UI, loads no JavaScript, registers no state and runs no queries.
protected array $features = [ 'views', 'export', 'import', 'bulk-actions', 'inline_edit', 'column_picker', 'bulk_edit', ];
Customise only where you want to
protected function columns(): array { return [ 'name', 'email', 'department.name' => 'Department', 'salary' => ['format' => 'currency:USD', 'align' => 'end'], 'created_at', ]; }
Features
| Columns | Automatic discovery · type detection · relationship columns · computed attributes · formatting · built-in renderers (progress, rating, sparkline, chips, avatar) · picker that can add any column, including through relations · drag reordering · resizing |
| Querying | Global search · per-column search · Dynamics-style filter builder with nested AND/OR groups · multi-column sorting · server-side pagination · soft deletes |
| Views | User views · system views · developer presets · default-view precedence · versioned JSON state · optional URL sync |
| Editing | Inline editing with validation · inline create · bulk edit over a selection · bulk actions · row actions · toolbar actions |
| Output | Print view from an editable Blade template · summary row (sum, avg, min, max, count) over the filtered set |
| Data | CSV and XLSX export (current page / view / all / selected) · import with mapping, preview, per-row errors and a downloadable error report · queued transfers with progress |
| UI | Bootstrap 5 · Tailwind · two framework-free themes (minimal, bordered) · custom themes in one array · sticky columns · row detail panels · infinite scroll · faceted filter counts · RTL and LTR · Arabic, Hebrew, English, Russian · responsive · keyboard accessible · ARIA |
| Engineering | No N+1 · constant query count · streaming exports · metadata caching · strict server-side validation of every client input · 120 tests · PHPStan level 5 |
Performance, stated as budgets
| Queries to render a page | 2 + one per eager-loaded relation, regardless of row count |
| Boot requests | zero — the first page is rendered server-side |
| Initial JavaScript | one ~14 KB module; feature modules load on first use |
| Export memory | flat, whether it is 10 rows or 10 million |
Model::all() is never called. Filter dropdowns are paginated DISTINCT
queries, not Department::all(). Relationship sorting uses a correlated
subquery, not a join.
Security, stated as a checklist
Every client input is re-derived server-side: table keys resolve through an
allowlist, sort and filter fields must resolve through the metadata engine,
operators come from a closed enum, values are coerced and bound, selected ids
are re-queried through the table's own scope, and edits are re-fetched through
it too — so query() is a hard boundary that no request can escape.
Full checklist in docs/security.md.
Requirements
PHP 8.2+ · Laravel 10, 11, 12 or 13 · MySQL, MariaDB, PostgreSQL or SQLite.
No Livewire. No Alpine. No jQuery. No npm. No CSS framework required. (It works happily inside a Livewire app — it just doesn't need one. The reasoning is in docs/architecture.md.)
Documentation
Installation · Quick start · Table class · Columns · Filters · Views · Editing & actions · Export & import · Themes · Localization & RTL · Performance · Security · Architecture · Extending · Troubleshooting
Demo
An interactive example application lives in demo/. Every example
renders a real table and shows the real file that produced it.
cd demo composer install php artisan dynamic-table:demo # migrate + seed php artisan serve
Then open /dynamic-table/examples.
Contributing
See CONTRIBUTING.md. Run composer test, composer analyse
and composer lint before opening a pull request.
Security
Please report vulnerabilities privately to shwaeki98@gmail.com.
Licence
MIT. See LICENSE.
No dependency of this package carries a copyleft or commercial licence — that constraint drove real architectural decisions, documented in docs/architecture.md.




