Filament: Table Tabs - Dynamically from Database

Filament Tables allow you to implement tabs easily. But did you know you can specify the tab names/values dynamically from the database, also controlling the order in which they appear? Let's take a look.

Customer Tabs

In this example, we have the following database table schema and Models.

database/migrations/XXXXXX_create_tiers_table.php

Schema::create('tiers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('order_column');
$table->timestamps();
});

database/migrations/XXXXXX_create_customers_table.php

use App\Models\Tier;
 
// ...
 
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Tier::class)->nullable()->constrained();
$table->string('full_name');
$table->timestamps();
});

app/Models/Tier.php

class Tier extends Model
{
// ...
 
protected $guarded = [];
 
public function customers(): HasMany
{
return $this->hasMany(Customer::class);
}
}

app/Models/Customer.php

class Customer extends Model
{
// ...
 
protected $guarded = [];
 
public function tier(): BelongsTo
{
return $this->belongsTo(Tier::class);
}
}

To add tabs, we must define the getTabs() method to your List<Resource>.php file. In this case, it is ListCustomers.

app/Filament/Resources/CustomerResource/Pages/ListCustomers.php

namespace App\Filament\Resources\CustomerResource\Pages;
 
use App\Filament\Resources\CustomerResource;
use App\Models\Tier;
use Filament\Actions;
use Filament\Resources\Components\Tab;
use Filament\Resources\Pages\ListRecords;
 
class ListCustomers extends ListRecords
{
protected static string $resource = CustomerResource::class;
 
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
 
 
public function getTabs(): array
{
$tabs = ['all' => Tab::make('All')->badge($this->getModel()::count())];
 
$tiers = Tier::orderBy('order_column', 'asc')
->withCount('customers')
->get();
 
foreach ($tiers as $tier) {
$name = $tier->name;
$slug = str($name)->slug()->toString();
 
$tabs[$slug] = Tab::make($name)
->badge($tier->customers_count)
->modifyQueryUsing(function ($query) use ($tier) {
return $query->where('tier_id', $tier->id);
});
}
 
return $tabs;
}
}

When returning the tabs array, the index of that array is a value of the activeTab URL parameter. So, we can generate a slug from the Tier name instead of just having a number.

//... /admin/customers?activeTab=platinum
$slug = str($name)->slug()->toString();

Tabs can have badges. The badge() method also accepts closures to display data depending on your custom logic. In our case, we show the Customer count in that Tier.

->badge($tier->customers_count)

Eloquent Query is modified with the ->modifyQueryUsing() method to filter records. Here, we extend the query to select Customers with the tier_id of the activeTab.

->modifyQueryUsing(function ($query) use ($tier) {
return $query->where('tier_id', $tier->id);
});

Tier tabs are sorted by the order_column column in ascending order.

$tiers = Tier::orderBy('order_column', 'asc')

You can change the order of tabs by modifying the order_column value on the EditTier page. Optionally, you can reorder rows directly on the ListTiers page by adding these methods to the TierResource@table method.

->defaultSort('order_column')
->reorderable('order_column')

Reorder Tiers

Reordered Tabs

Implemented Tier and Customer Resources are as follows.

app/Filament/Resources/TierResource.php

use Filament\Forms\Components\TextInput;
use Filament\Tables\Columns\TextColumn;
 
class TierResource extends Resource
{
// ...
 
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),
TextInput::make('order_column')
->required()
->numeric(),
]);
}
 
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('order_column'),
TextColumn::make('name'),
TextColumn::make('customers_count')
->counts('customers')
->badge(),
])
->defaultSort('order_column')
->reorderable('order_column')
// ...
}
}

app/Filament/Resources/CustomerResource.php

use App\Models\Tier;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Tables\Columns\TextColumn;
 
class CustomerResource extends Resource
{
// ...
 
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('full_name')
->required(),
Select::make('tier_id')
->label('Tier')
->options(Tier::pluck('name', 'id')),
]);
}
 
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('full_name'),
TextColumn::make('tier.name')
->badge(),
])
// ...
}
}

Congratulations! You've successfully implemented dynamic Tabs for your Filament Table.


If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 52 courses (943 lessons, total 46 h 42 min)
  • 75 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials