Template Column
Render table cells with a custom server-side Twig template
TemplateColumn delegates cell rendering to a Twig template. Use it when you need server-side HTML that depends on row state, complex conditionals, or components that are impractical to build as a JavaScript render callback.
Basic Usage
use Pentiminax\UX\DataTables\Column\TemplateColumn;
TemplateColumn::new('status_display', 'Status')
->setField('status')
->setTemplate('datatable/columns/user_status.html.twig');
The column name (status_display) is the key used in mapRow(). setField() tells the row mapper which property to read from the row object.
Template Context
Inside the template, the following variables are available:
| Variable | Value |
|---|---|
row | The object passed to mapRow() (the projected DTO when a page projector is active, otherwise the source object) |
source | The original hydrated object. Same reference as row when no projector is active |
payload | The array returned by mapRow(). Use it to read a mapped key other than this cell’s |
data | The resolved field value for this cell |
column | Serialized column configuration array |
Read domain properties from row, this cell’s value from data, and any other mapped key from payload.
payload holds the row as the earlier pipeline stages left it, so cells rendered by other TemplateColumns and the row action metadata are absent from it. A payload entry can also be null while data is set: a null mapped value falls back to reading the object, and normalization writes null for objects that are not DateTimeInterface, BackedEnum, or Stringable.
entity is a deprecated alias of row in TemplateColumn templates. Prefer row. Collapsible detail rows and edit modals expose their own unrelated entity variable, which is not deprecated.
Example template:
{# templates/datatable/columns/user_status.html.twig #}
<span class="badge bg-{{ data == 'active' ? 'success' : 'danger' }}">
{{ data|capitalize }}
</span>
Passing Parameters
Pass static parameters to the template via setTemplate():
TemplateColumn::new('actions', 'Actions')
->setTemplate('datatable/columns/row_actions.html.twig', [
'editRoute' => 'admin_user_edit',
]);
Parameters are merged into the template context. The keys row, source, payload, data, column, and entity are reserved: passing one throws an InvalidArgumentException.
API Reference
| Method | Description |
|---|---|
TemplateColumn::new(string $name, string $title = '') | Creates a new TemplateColumn (type: html) |
setTemplate(string $template, array $parameters = []) | Set the Twig template path and optional static parameters. Throws on an empty path, and on a parameter using a reserved context key. |
getTemplate(): string | Returns the configured template path. Throws if not set. |
getTemplateParameters(): array | Returns the static parameters passed to the template |
Complete Example
use Pentiminax\UX\DataTables\Attribute\AsDataTable;
use Pentiminax\UX\DataTables\Column\NumberColumn;
use Pentiminax\UX\DataTables\Column\TemplateColumn;
use Pentiminax\UX\DataTables\Column\TextColumn;
use Pentiminax\UX\DataTables\Model\AbstractDataTable;
#[AsDataTable(Product::class)]
final class ProductsDataTable extends AbstractDataTable
{
public function configureColumns(): iterable
{
yield NumberColumn::new('id', 'ID');
yield TextColumn::new('name', 'Name');
yield TemplateColumn::new('stock_badge', 'Stock')
->setField('stock')
->setTemplate('datatable/columns/stock_badge.html.twig');
}
protected function mapRow(mixed $row): array
{
return [
'id' => $row->getId(),
'name' => $row->getName(),
'stock_badge' => $row->getStock(),
];
}
}
{# templates/datatable/columns/stock_badge.html.twig #}
{% set variant = data > 10 ? 'success' : (data > 0 ? 'warning' : 'danger') %}
<span class="badge text-bg-{{ variant }}">{{ data }}</span>