Search by

felipearnold / filament-stepped-tabs

felipeArnold

Chevron-style stepped tabs navigation with counters for Filament (and any Livewire) pages.

Package info

github.com/felipeArnold/filament-stepped-tabs

pkg:composer/felipearnold/filament-stepped-tabs

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 5

Open Issues: 0

v1.1.1 2026-10-03 23:13 UTC

This package is auto-updated.

Last update: 2026-10-03 23:19:45 UTC


README

Filament Stepped Tabs

Chevron-style stepped tabs navigation with counters, for Filament (and any Livewire) pages.

Why

Filament's built-in Tabs component renders a pill-style tab bar. This package renders the same "steps"/breadcrumb look — chevron-shaped segments, a bold label, a small counter underneath, active step highlighted — and plugs into any Livewire component, not just Filament resource pages.

The core (StepTab builder + InteractsWithSteppedTabs trait) has no dependency on Filament internals — it only requires Livewire. The Blade view uses <x-filament::icon> (from filament/support, present in every Filament major) for the optional per-step icon.

Installation

composer require felipearnold/filament-stepped-tabs

Usage

Filament v4/v5 ListRecords with getTabs() (recommended)

Keep your regular Filament tabs and add HasSteppedTabs. The page's getTabs() is rendered as stepped tabs: label and icon come from each Tab, and the counter is the number of records of that tab with the current table filters and search applied.

use FelipeArnold\FilamentSteppedTabs\Concerns\HasSteppedTabs;
use Filament\Schemas\Components\Tabs\Tab;

class ListInvoices extends ListRecords
{
    use HasSteppedTabs;

    public function getTabs(): array
    {
        return [
            'draft' => Tab::make('Drafts')
                ->icon('heroicon-o-pencil-square')
                ->modifyQueryUsing(fn (Builder $query) => $query->where('status', 'draft')),
            'all' => Tab::make('All')->icon('heroicon-o-queue-list'),
        ];
    }
}

The active step is bound to Filament's own $activeTab property, so ?tab= in the URL, the default tab and modifyQueryUsing() keep working unchanged. Each step runs one count() query.

Custom steps on any Livewire component

1. Add the trait to your Livewire component

use FelipeArnold\FilamentSteppedTabs\Concerns\InteractsWithSteppedTabs;

class ListEnvelopes extends ListRecords
{
    use InteractsWithSteppedTabs;

    public function getDefaultActiveStep(): ?string
    {
        return 'sent';
    }
}

2. Build your steps with StepTab

use FelipeArnold\FilamentSteppedTabs\StepTab;

public function getSteps(): array
{
    $counts = Envelope::query()->where('tenant_id', $tenant->id)
        ->selectRaw('status, count(*) as total')->groupBy('status')->pluck('total', 'status');

    return [
        StepTab::make('draft')->label('Rascunhos')->icon('heroicon-o-pencil-square')->count($counts->get('draft', 0))->toArray(),
        StepTab::make('cancelled')->label('Cancelados')->icon('heroicon-o-x-circle')->count($counts->get('cancelled', 0))->toArray(),
        StepTab::make('expired')->label('Expirados')->icon('heroicon-o-calendar')->count($counts->get('expired', 0))->toArray(),
        StepTab::make('sent')->label('Em andamento')->icon('heroicon-o-paper-airplane')->count($counts->get('sent', 0))->toArray(),
        StepTab::make('signed')->label('Assinados')->icon('heroicon-o-check-circle')->count($counts->get('signed', 0))->toArray(),
        StepTab::make('all')->label('Todos')->icon('heroicon-o-inbox')->count($counts->sum())->toArray(),
    ];
}

3. Render it and filter your query by $this->activeStep

Filament v4/v5 (inside a ListRecords page, replacing getTabsContentComponent()):

use Filament\Schemas\Components\Component;
use Filament\Schemas\Components\View;

public function getTabsContentComponent(): Component
{
    return View::make('filament-stepped-tabs::components.nav')
        ->viewData(['steps' => $this->getSteps(), 'activeStep' => $this->activeStep]);
}

protected function getTableQuery(): Builder
{
    $query = parent::getTableQuery();

    return $this->activeStep && $this->activeStep !== 'all'
        ? $query->where('status', $this->activeStep)
        : $query;
}

Filament v3 (no Schemas package — render inside the page's Blade view or via a renderHook):

{{-- resources/views/filament/resources/envelopes/pages/list-envelopes.blade.php --}}
<x-filament-panels::page>
    @include('filament-stepped-tabs::components.nav', ['steps' => $this->getSteps(), 'activeStep' => $this->activeStep])

    {{ $this->table }}
</x-filament-panels::page>

Plain Blade / any Livewire component:

<x-filament-stepped-tabs::nav :steps="$this->getSteps()" :active-step="$activeStep" />

The view also accepts property (default activeStep): the Livewire property set when a step is clicked.

Step options

Method Description
StepTab::make(string $key) Unique key ([a-z0-9_-]+), used for activeStep matching
->label(string $label) Display label (defaults to the key)
->count(int $count) Counter shown under the label
->icon(string|BackedEnum|Htmlable|null $icon) Optional icon (name or Heroicon enum), rendered via x-filament::icon
->color(?string $color) Reserved for future theming

Translations

The step counter ("1 item", "3 items") follows the app locale. Bundled: en, pt_BR and pt_PT. Publish to customize or add a locale:

php artisan vendor:publish --tag="filament-stepped-tabs-translations"

Testing

composer test

License

MIT.