Skip to content

Text column

TextColumn renders a value as text. It is sortable and filterable, and carries display modifiers for the common value types a text cell holds.

TextColumn::make('name')->label('Name')->link('/people/{value}')->sortable();
TextColumn::make('email')->label('Email')->link('mailto:{value}')->copyable();
TextColumn::make('joined_at')->label('Joined')->date()->sortable();

->date(), ->time(), and ->dateTime() format a date/time value for the viewer’s locale and timezone. Pass a DateTimeStyle case — Short, Medium (the default), Long, or Full — to control the style. A dated column filters as a date.

use Lattice\Ui\Enums\DateTimeStyle;
TextColumn::make('created_at')->date();
TextColumn::make('updated_at')->dateTime(DateTimeStyle::Short);

->link('/products/{value}') renders the value as a link; {value} is substituted with the cell value, and any other {key} in braces with that row field. Pass external: true for an outbound link that opens in a new tab.

TextColumn::make('email')->link('mailto:{value}')->copyable();
TextColumn::make('homepage')->link('{value}', external: true);

When a template is not enough, pass a closure instead — it runs on the server per row, receives $row (the projected row array) and $value (this column’s value) by name, and returns the href. Return null to leave that row’s cell as plain text.

TextColumn::make('name')->link(fn (array $row): string => route('customers.show', $row['id']));

->popover() renders the value as a trigger that opens a popover. The closure runs on the server per row — receiving $row and $value like a link closure — and returns the popover’s content component, or null for no popover on that row. Combined with a lazy fragment, the content loads from the server when the popover first opens:

TextColumn::make('customer_name')->popover(fn (array $row) => Fragment::lazy(
CustomerCardFragment::class,
['customerId' => $row['customer_id']],
));

->copyable() adds a click-to-copy affordance to the cell.

TextColumn::make('api_token')->copyable();

->badge() renders the value as a coloured pill. The colour is read from a sibling field on the row — ->badge('status_color') reads it from status_color, defaulting to the color field. That field may hold a colour name (green, success, …) or any CSS colour — a hex value stored by a ColorPicker field works as-is — falling back to gray when unset or unrecognized. For a fixed value-to-colour map instead, use a dedicated Badge column.

TextColumn::make('status')->badge('status_color');

->multiple('name') draws the value from a to-many relation named by the column key, reading name from each related row and rendering the values as a list. It filters through the relation and is never sortable — see relation columns.

TextColumn::make('tags')->multiple('name')->badge('color');