Filament Table Builder has dozens of ways how to customize column values. In this lesson, I will touch on the most commonly used ones.
Show as Tags/Badges
Filament has a general concept of a "Badge", I personally call it a "Tag", which is just a visual representation of a text/number surrounded by a border.
Let's take a look at it by just adding ->badge()
to two columns in our Products table: status
and tags
.
return $table ->columns([ Tables\Columns\TextColumn::make('name'), Tables\Columns\TextColumn::make('price'), Tables\Columns\TextColumn::make('status') ->badge(), Tables\Columns\TextColumn::make('category.name'), Tables\Columns\TextColumn::make('tags.name') ->badge(), ])
Here's the visual result:
As you can see, Filament automatically wraps the text as a "badge". Not only does it work for a simple TextColumn
, but also, in the case of the belongsToMany
relationship, it shows multiple badges instead of a comma-separated text.
You can also specify different colors for different badge values.
Tables\Columns\TextColumn::make('status') ->badge() ->color(fn (string $state): string => match ($state) { 'in stock' => 'primary', 'sold out' => 'danger', 'coming soon' => 'info', }),
Here's how it looks now:
You can choose the colors from these options:
- danger
- gray
- info
- primary
- success
- warning
Clickable URL Column
You would often want some text to act as a link to another section or page. For example, the Product "Category" column could link to the Edit Category page or to a page of Products filtered by that Category.
For that, you can add the ->url()
method to your column.
Tables\Columns\TextColumn::make('category.name') ->url(fn (Product $product): string => CategoryResource::getUrl('edit', ['record' => $product->category_id])),
Notice: to be honest, I prefer the short PHP functions syntax only if the line of code is actually short. In this case, for readability, I would choose this:
Tables\Columns\TextColumn::make('category.name') ->url(function (Product $product): string { return CategoryResource::getUrl('edit', [ 'record' => $product->category_id ]); }),
And then, clicking on the category name would lead to the page something like /admin/categories/1/edit
or similar. In our project, we don't have the page for Category Edit, as we generated that resource as --simple
, so this was just an illustrative example.
As you can see, you can get the URL to any of the Filament Resources pages with the method getUrl()
:
-
CategoryResource::getUrl();
: returns/admin/categories
-
CategoryResource::getUrl('create');
: returns/admin/categories/create
-
CategoryResource::getUrl('edit', ['record' => 1]);
: returns/admin/categories/1/edit
Different Label on Top
By default, Filament is trying to "guess" the column name in the header of the table from the field name, just putting the Title Case:
-
TextColumn::make('name')
-> "Name" -
TextColumn::make('category.name')
-> "Category" -
TextColumn::make('tags.name')
-> "Tags"
But you can easily override it just by adding ->label()
to the chained methods.
Tables\Columns\TextColumn::make('category.name') ->label('Category name'),
Here's the visual result:
Column Alignment
Also, you can specify a different alignment than the default "left". Again, it's as easy as adding a method to the chain:
Tables\Columns\TextColumn::make('price') ->sortable() ->money('usd') ->getStateUsing(function (Product $record): float { return $record->price / 100; }) ->alignEnd(),
Shorter methods for each possible alignment:
- alignLeft()
- alignCenter()
- alignRight()
- alignJustify()
- alignStart()
- alignEnd()
Or, you can use a longer syntax with one standard method and specific Enum constants for the alignments:
use Filament\Support\Enums\Alignment; // ...Tables\Columns\TextColumn::make('price') ->alignment(Alignment::End)
Date Fields Formatting
If you want to show a timestamp field like created_at
, you may choose which part to show: full date and time, only date, or "x days ago".
Just pick one of the methods to attach to the chain with the optional format parameter:
Tables\Columns\TextColumn::make('created_at') ->dateTime(),
Tables\Columns\TextColumn::make('created_at') ->dateTime('m/d/Y H:i'),
Tables\Columns\TextColumn::make('created_at') ->date(),
// This will run "diffForHumans" under the hoodTables\Columns\TextColumn::make('created_at') ->since(),
These are just a few typical customizations of the table columns. For more examples and methods, please refer to the official documentation.
Hello Povilas, first I would like to thank you for this amazing content. I've followed part of this course, and I've a little problem and you doesn't talk about that and probably you never tested it. I've a file upload at form like this: Forms\Components\FileUpload::make('avatarurl') ->image() ->disk('private') ->visibility('private') ->directory('profile-photos') ->maxSize(1024) ->imageResizeMode('cover') ->getUploadedFileNameForStorageUsing( fn(TemporaryUploadedFile $file): string => (string)str($file->getClientOriginalName()) ->prepend('profile-'), ),
And at table I've this: Tables\Columns\ImageColumn::make('avatarurl')->circular() ->disk('private') ->visibility('private'),
and the final result is I can't show the image on the table. If I've the visibility 'public' everything is ok. Can you help me? Thank You!
Hi Pedro. Well, to me it's pretty obvious, if you want the file to be PRIVATE, it means you're HIDING it from everyone, including the Filament table. What are you actually trying to achieve here? Why private?
For now i was testing with images, but in the future it can be private documents for example. And filament documentation talks about this "Filament can generate temporary URLs to render private images, you may set the visibility() to private" (https://filamentphp.com/docs/3.x/tables/columns/image#managing-the-image-disk).
Another example is, is case of images they are inside a panel, if I've the image url and I'am not logged in, it doesn't make sense to be able to access the image. What is your opinion?
Well it's still a weird scenario to me, personally. I understand that Filament may allow it, but as you can see it doesn't work properly, for some reason, I haven't debugged it, personally.
I probably need to schedule some time on a proper tutorial about private/public file uploads in Filament, it's a deep topic with many use cases. Adding to the (already huge) to-do list.
I was going to search at github filament pull request, some people have this problems with S3.
When I add the URL for the category, and I click the link, show error: Missing required parameter for [Route: filament.admin.resources.categories.edit] [URI: admin/categories/{record}/edit] [Missing parameter: record].
@Zhtekdev I initially got it too, but you can see a note saying: "In our project, we don't have the page for Category Edit, as we generated that resource as --simple, so this was just an illustrative example." That's why you get the error.
The URL examples you show all reference other Filament desintations. Is it possible to fall back to Laravel route() functions in the url() method? Would it need a callback to reference the current model?
Tables\Columns\TextColumn::make('category.name') ->url(fn (Product $product): string => CategoryResource::getUrl('create', ['record' => $product->category_id])),
I'm not sure about the setup nor the URL that opens, but if it's a url with
query
parameter in it - you can simply dorequest()->query('record')
and that should do the trickThanks, worked perfectly.
If category is simple resource, this not works! because does have edit route!
the route to category edit won't work because we are using modal for editing the categories.