UX DataTables
Overview
pentiminax/ux-datatables integrates DataTables.net into Symfony. You declare a class extending AbstractDataTable, annotate it with #[AsDataTable(Entity::class)], define columns, and render with the Twig render_datatable() function. A Stimulus controller (@pentiminax/ux-datatables/datatable) lazy-loads DataTables and its extensions.
Decision tree: client-side vs server-side
Dataset < ~5k rows AND can load all upfront?
├── yes → CLIENT-SIDE: define columns, optionally setData()/data(). Browser paginates/filters/sorts.
└── no → SERVER-SIDE: configureDataTable(fn) → $table->serverSide()->processing()
DB handles paging/filter/sort. Doctrine provider auto-wired from #[AsDataTable(Entity::class)].
MUST import bundle routes (see references/server-side.md).
Minimal example
use App\Entity\User;
use Pentiminax\UX\DataTables\Attribute\AsDataTable;
use Pentiminax\UX\DataTables\Column\{DateColumn, NumberColumn, TextColumn};
use Pentiminax\UX\DataTables\Model\{AbstractDataTable, Action, Actions, DataTable};
#[AsDataTable(User::class)]
final class UserDataTable extends AbstractDataTable
{
public function configureColumns(): iterable
{
return [
NumberColumn::new('id', 'ID'),
TextColumn::new('email', 'Email'),
DateColumn::new('createdAt', 'Created')->setFormat('d/m/Y'),
];
}
public function configureDataTable(DataTable $table): DataTable
{
return $table->serverSide()->processing()->pageLength(25);
}
public function configureActions(Actions $actions): Actions
{
return $actions->add(Action::edit())->add(Action::delete()->askConfirmation('Delete?'));
}
}
Controller + Twig:
public function index(UserDataTable $table, Request $request): Response
{
$table->handleRequest($request);
if ($table->isRequestHandled()) {
return $table->getResponse();
}
return $this->render('user/index.html.twig', ['table' => $table]);
}
{{ render_datatable(table) }}
Scaffold from an entity: php bin/console make:datatable.
References (read on demand)
references/defining-a-datatable.md — AbstractDataTable, #[AsDataTable], the configure*() hooks, data providers, customizeQueryBuilder(), page projection (projectPage()).
references/columns.md — all 11 column types + shared AbstractColumn methods.
references/server-side.md — server-side wiring, route import, Stimulus events, custom Ajax, computed columns (setOrderExpression()).
references/extensions.md — Buttons, Select, Responsive, ColumnControl, Scroller, KeyTable, ColReorder, FixedColumns.
references/actions.md — row actions, permissions, conditional display.
references/filters.md — declarative filter bar (configureFilters()): Text, Select, Ternary, DateRange, generic Filter (server-side Doctrine).
references/api-platform.md — API Platform + Mercure integration (both opt-in).
references/gotchas.md — common mistakes and fixes.
Common mistakes (see gotchas.md)
- Server-side actions do nothing → bundle routes not imported.
- Server-side with no Doctrine data → missing
entityClass in #[AsDataTable].
- API Platform / Mercure behavior absent → must opt in explicitly (
apiPlatform: true, mercure()).
Source: pentiminax/ux-datatables — distributed by TomeVault.
1---2name: ux-datatables3description: Use when building, configuring, or debugging DataTables with the pentiminax/ux-datatables Symfony bundle — defining DataTable classes, columns, client-side vs server-side mode, extensions, row actions, or API Platform / Mercure integration.4---56# UX DataTables78## Overview910`pentiminax/ux-datatables` integrates [DataTables.net](https://datatables.net) into Symfony. You declare a class extending `AbstractDataTable`, annotate it with `#[AsDataTable(Entity::class)]`, define columns, and render with the Twig `render_datatable()` function. A Stimulus controller (`@pentiminax/ux-datatables/datatable`) lazy-loads DataTables and its extensions.1112## Decision tree: client-side vs server-side1314```15Dataset < ~5k rows AND can load all upfront?16├── yes → CLIENT-SIDE: define columns, optionally setData()/data(). Browser paginates/filters/sorts.17└── no → SERVER-SIDE: configureDataTable(fn) → $table->serverSide()->processing()18 DB handles paging/filter/sort. Doctrine provider auto-wired from #[AsDataTable(Entity::class)].19 MUST import bundle routes (see references/server-side.md).20```2122## Minimal example2324```php25use App\Entity\User;26use Pentiminax\UX\DataTables\Attribute\AsDataTable;27use Pentiminax\UX\DataTables\Column\{DateColumn, NumberColumn, TextColumn};28use Pentiminax\UX\DataTables\Model\{AbstractDataTable, Action, Actions, DataTable};2930#[AsDataTable(User::class)]31final class UserDataTable extends AbstractDataTable32{33 public function configureColumns(): iterable34 {35 return [36 NumberColumn::new('id', 'ID'),37 TextColumn::new('email', 'Email'),38 DateColumn::new('createdAt', 'Created')->setFormat('d/m/Y'),39 ];40 }4142 public function configureDataTable(DataTable $table): DataTable43 {44 return $table->serverSide()->processing()->pageLength(25);45 }4647 public function configureActions(Actions $actions): Actions48 {49 return $actions->add(Action::edit())->add(Action::delete()->askConfirmation('Delete?'));50 }51}52```5354Controller + Twig:55```php56public function index(UserDataTable $table, Request $request): Response57{58 $table->handleRequest($request);59 if ($table->isRequestHandled()) {60 return $table->getResponse();61 }62 return $this->render('user/index.html.twig', ['table' => $table]);63}64```65```twig66{{ render_datatable(table) }}67```6869Scaffold from an entity: `php bin/console make:datatable`.7071## References (read on demand)7273- `references/defining-a-datatable.md` — `AbstractDataTable`, `#[AsDataTable]`, the `configure*()` hooks, data providers, `customizeQueryBuilder()`, page projection (`projectPage()`).74- `references/columns.md` — all 11 column types + shared `AbstractColumn` methods.75- `references/server-side.md` — server-side wiring, route import, Stimulus events, custom Ajax, computed columns (`setOrderExpression()`).76- `references/extensions.md` — Buttons, Select, Responsive, ColumnControl, Scroller, KeyTable, ColReorder, FixedColumns.77- `references/actions.md` — row actions, permissions, conditional display.78- `references/filters.md` — declarative filter bar (`configureFilters()`): Text, Select, Ternary, DateRange, generic Filter (server-side Doctrine).79- `references/api-platform.md` — API Platform + Mercure integration (both opt-in).80- `references/gotchas.md` — common mistakes and fixes.8182## Common mistakes (see gotchas.md)83841. Server-side actions do nothing → bundle routes not imported.852. Server-side with no Doctrine data → missing `entityClass` in `#[AsDataTable]`.863. API Platform / Mercure behavior absent → must opt in explicitly (`apiPlatform: true`, `mercure()`).8788---89> Source: [pentiminax/ux-datatables](https://github.com/pentiminax/ux-datatables) — distributed by [TomeVault](https://tomevault.io).90<!-- tomevault:4.0:skill_md:2026-06-29 -->