Overview
Introduction
Column classes can be found in the Filament\Tables\Columns namespace. They reside within the $table->columns() method. Filament includes a number of columns built-in:
Editable columns allow the user to update data in the database without leaving the table:
You may also create your own custom columns to display data however you wish.
Columns may be created using the static make() method, passing its unique name. Usually, the name of a column corresponds to the name of an attribute on an Eloquent model. You may use "dot notation" to access attributes within relationships:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
TextColumn::make('author.name')
Column content (state)
Columns may feel a bit magic at first, but they’re designed to be simple to use and optimized to display data from an Eloquent record. Despite this, they’re flexible and you can display data from any source, not just an Eloquent record attribute.
The data that a column displays is called its "state". When using a panel resource, the table is aware of the records it is displaying. This means that the state of the column is set based on the value of the attribute on the record. For example, if the column is used in the table of a PostResource, then the title attribute value of the current post will be displayed.
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
If you want to access the value stored in a relationship, you can use "dot notation". The name of the relationship that you would like to access data from comes first, followed by a dot, and then the name of the attribute:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('author.name')
You can also use "dot notation" to access values within a JSON / array column on an Eloquent model. The name of the attribute comes first, followed by a dot, and then the key of the JSON object you want to read from:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('meta.title')
Setting the state of a column
You can pass your own state to a column by using the state() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
->state('Hello, world!')
The state() method also accepts a function to dynamically calculate the state. You can inject various utilities into the function as parameters.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Column | Filament\Tables\Columns\Column | $column | The current column instance. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current table row. |
| Row loop | stdClass | $rowLoop | The <a href="https://laravel.com/docs/blade#the-loop-variable" target="_blank">row loop</a> object for the current table row. |
| State | mixed | $state | The current value of the column, based on the current table row. |
| Table | Filament\Tables\Table | $table | The current table instance. |
Setting the default state of a column
When a column is empty (its state is null), you can use the default() method to define alternative state to use instead. This method will treat the default state as if it were real, so columns like image or color will display the default image or color.
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
->default('Untitled')
Adding placeholder text if a column is empty
Sometimes you may want to display placeholder text for columns with an empty state, which is styled as a lighter gray text. This differs from the default value, as the placeholder is always text and not treated as if it were real state.
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
->placeholder('Untitled')

Displaying data from relationships
You may use "dot notation" to access columns within relationships. The name of the relationship comes first, followed by a period, followed by the name of the column to display:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('author.name')
Counting relationships
If you wish to count the number of related records in a column, you may use the counts() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('users_count')->counts('users')
In this example, users is the name of the relationship to count from. The name of the column must be users_count, as this is the convention that Laravel uses for storing the result.
If you'd like to scope the relationship before counting, you can pass an array to the method, where the key is the relationship name and the value is the function to scope the Eloquent query with:
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
TextColumn::make('users_count')->counts([
'users' => fn (Builder $query) => $query->where('is_active', true),
])
Determining relationship existence
If you simply wish to indicate whether related records exist in a column, you may use the exists() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('users_exists')->exists('users')
In this example, users is the name of the relationship to check for existence. The name of the column must be users_exists, as this is the convention that Laravel uses for storing the result.
If you'd like to scope the relationship before checking existence, you can pass an array to the method, where the key is the relationship name and the value is the function to scope the Eloquent query with:
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
TextColumn::make('users_exists')->exists([
'users' => fn (Builder $query) => $query->where('is_active', true),
])
Aggregating relationships
Filament provides several methods for aggregating a relationship field, including avg(), max(), min() and sum(). For instance, if you wish to show the average of a field on all related records in a column, you may use the avg() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('users_avg_age')->avg('users', 'age')
In this example, users is the name of the relationship, while age is the field that is being averaged. The name of the column must be users_avg_age, as this is the convention that Laravel uses for storing the result.
If you'd like to scope the relationship before aggregating, you can pass an array to the method, where the key is the relationship name and the value is the function to scope the Eloquent query with:
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
TextColumn::make('users_avg_age')->avg([
'users' => fn (Builder $query) => $query->where('is_active', true),
], 'age')
Setting a column's label
By default, the label of the column, which is displayed in the header of the table, is generated from the name of the column. You may customize this using the label() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('name')
->label('Full name')
As well as allowing a static value, the label() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Column | Filament\Tables\Columns\Column | $column | The current column instance. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current table row. |
| Row loop | stdClass | $rowLoop | The <a href="https://laravel.com/docs/blade#the-loop-variable" target="_blank">row loop</a> object for the current table row. |
| State | mixed | $state | The current value of the column, based on the current table row. |
| Table | Filament\Tables\Table | $table | The current table instance. |
Customizing the label in this way is useful if you wish to use a translation string for localization:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('name')
->label(__('columns.name'))
Sorting
Columns may be sortable, by clicking on the column label. To make a column sortable, you must use the sortable() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('name')
->sortable()

Using the name of the column, Filament will apply an orderBy() clause to the Eloquent query. This is useful for simple cases where the column name matches the database column name. It can also handle relationships.
However, many columns are not as simple. The state of the column might be customized, or using an Eloquent accessor. In this case, you may need to customize the sorting behavior.
You can pass an array of real database columns in the table to sort the column with:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('full_name')
->sortable(['first_name', 'last_name'])
In this instance, the full_name column is not a real column in the database, but the first_name and last_name columns are. When the full_name column is sorted, Filament will sort the table by the first_name and last_name columns. The reason why two columns are passed is that if two records have the same first_name, the last_name will be used to sort them. If your use case doesn’t require this, you can pass only one column in the array if you wish.
You may also directly interact with the Eloquent query to customize how sorting is applied for that column:
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
TextColumn::make('full_name')
->sortable(query: function (Builder $query, string $direction): Builder {
return $query
->orderBy('last_name', $direction)
->orderBy('first_name', $direction);
})
The query parameter's function can inject various utilities as parameters.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Column | Filament\Tables\Columns\Column | $column | The current column instance. |
| Direction | string | $direction | The direction that the column is currently being sorted on, either <code>'asc'</code> or <code>'desc'</code>. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent query builder | Illuminate\Database\Eloquent\Builder | $query | The query builder to modify. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current table row. |
| Row loop | stdClass | $rowLoop | The <a href="https://laravel.com/docs/blade#the-loop-variable" target="_blank">row loop</a> object for the current table row. |
| State | mixed | $state | The current value of the column, based on the current table row. |
| Table | Filament\Tables\Table | $table | The current table instance. |
Sorting by default
You may choose to sort a table by default if no other sort is applied. You can use the defaultSort() method for this:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->defaultSort('stock', direction: 'desc');
}
The second parameter is optional and defaults to 'asc'.
If you pass the name of a table column as the first parameter, Filament will use that column's sorting behavior (custom sorting columns or query function). However, if you need to sort by a column that doesn’t exist in the table or in the database, you should pass a query function instead:
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->defaultSort(function (Builder $query): Builder {
return $query->orderBy('stock');
});
}
Persisting the sort in the user's session
To persist the sorting in the user's session, use the persistSortInSession() method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->persistSortInSession();
}
Setting a default sort option label
To set a default sort option label, use the defaultSortOptionLabel() method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->defaultSortOptionLabel('Date');
}
Disabling default primary key sorting
By default, Filament will automatically add a primary key sort to the table query to ensure that the order of records is consistent. The primary key will be sorted in the same direction as the other sort column. If your table doesn't have a primary key, or you wish to disable this behavior, you can use the defaultKeySort(false) method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->defaultKeySort(false);
}
Searching
Columns may be searchable by using the text input field in the top right of the table. To make a column searchable, you must use the searchable() method:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('name')
->searchable()

By default, Filament will apply a where clause to the Eloquent query, searching for the column name. This is useful for simple cases where the column name matches the database column name. It can also handle relationships.
However, many columns are not as simple. The state of the column might be customized, or using an Eloquent accessor. In this case, you may need to customize the search behavior.
You can pass an array of real database columns in the table to search the column with:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('full_name')
->searchable(['first_name', 'last_name'])
In this instance, the full_name column is not a real column in the database, but the first_name and last_name columns are. When the full_name column is searched, Filament will search the table by the first_name and last_name columns.
You may also directly interact with the Eloquent query to customize how searching is applied for that column:
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
TextColumn::make('full_name')
->searchable(query: function (Builder $query, string $search): Builder {
return $query
->where('first_name', 'like', "%{$search}%")
->orWhere('last_name', 'like', "%{$search}%");
})
The query parameter's function can inject various utilities as parameters.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Column | Filament\Tables\Columns\Column | $column | The current column instance. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent query builder | Illuminate\Database\Eloquent\Builder | $query | The query builder to modify. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current table row. |
| Row loop | stdClass | $rowLoop | The <a href="https://laravel.com/docs/blade#the-loop-variable" target="_blank">row loop</a> object for the current table row. |
| Search | string | $search | The current search input value. |
| State | mixed | $state | The current value of the column, based on the current table row. |
| Table | Filament\Tables\Table | $table | The current table instance. |


