Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

oliverbusk's avatar

FilamentPHP / Laravel - Sub pages using the Tabs component

I have a custom page, which I've created called "CompanyOverview". It's a simple page, with a blade view like so:

<x-filament-panels::page>
    <div class="flex flex-col gap-4" x-data="{ tab: 'shipments' }">
        <x-filament::tabs label="Content tabs">
            <x-filament::tabs.item @click="tab = 'shipments'" :alpine-active="'tab === \'shipments\''">
                Shipments
            </x-filament::tabs.item>
            <x-filament::tabs.item @click="tab = 'summary'" :alpine-active="'tab === \'summary\''">
                Summary
            </x-filament::tabs.item>

        </x-filament::tabs>    

        <div>
            <div x-show="tab === 'shipments'" x-cloak>
                <livewire:intercompany.table-shipment :filters="$filters" />
            </div>
            <div x-show="tab === 'summary'" x-cloak>
                
            </div>

        </div>
        
    </div>
</x-filament-panels::page>

As you can see, on this page, I simply include a Livewire component in my first tab. This component just renders a standard Filament table:

//table-shipments.blade.php
<div>
    {{ $this->table }}
</div>

Now, I want to add some other content under the Summary tab. Under here, I would like to render a lot of different widgets (it's basically an analytics page). So, I was thinking that it would be nice to be able to utilize just another custom page (or dashboard even), so I could just add the widgets using the getHeaderWidgets() method, and don't worry about the Blade / HTML part.

I have tried to create a custom page CompanySummary.php:

use Filament\Pages\Page;

class CompanySummary extends Page
{
    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    protected static string $view = 'filament.app.pages.company-summary';

    protected function getHeaderWidgets(): array
    {
        return [
           //I will place my widgets here.
        ];
    }

}

<div x-show="tab === 'summary'" x-cloak>
    @include('filament.app.pages.company-summary')
</div>

It renders the new page, however, it includes it as a new page within my existing page (e.g., two titles and filter actions) - where I essentially, would also like to use my original page filters'.

Is this possible?

0 likes
1 reply
LaryAI's avatar
Level 58

To achieve the desired functionality of rendering widgets under the "Summary" tab without duplicating the page structure, you can refactor your approach to include the widgets directly in the "CompanyOverview" page. Instead of creating a separate page for the summary, you can leverage the getHeaderWidgets() method within the same page or use a dedicated Livewire component for the summary section. Here's how you can do it:

  1. Create a Livewire Component for the Summary Tab:

    First, create a Livewire component that will handle the rendering of your widgets. This component will be used in the "Summary" tab.

    php artisan make:livewire SummaryWidgets
    
  2. Implement the Widgets in the Livewire Component:

    In the SummaryWidgets component, you can define the widgets you want to display.

    // app/Http/Livewire/SummaryWidgets.php
    
    namespace App\Http\Livewire;
    
    use Livewire\Component;
    use Filament\Widgets\Widget;
    
    class SummaryWidgets extends Component
    {
        public function render()
        {
            return view('livewire.summary-widgets', [
                'widgets' => $this->getWidgets(),
            ]);
        }
    
        protected function getWidgets(): array
        {
            return [
                // Instantiate your widgets here
                // Example: new SomeWidget(),
            ];
        }
    }
    
  3. Create the Blade View for the Livewire Component:

    Create a Blade view for the SummaryWidgets component to render the widgets.

    <!-- resources/views/livewire/summary-widgets.blade.php -->
    
    <div>
        @foreach ($widgets as $widget)
            {{ $widget->render() }}
        @endforeach
    </div>
    
  4. Include the Livewire Component in the Summary Tab:

    Update your "CompanyOverview" page to include the SummaryWidgets component in the "Summary" tab.

    <x-filament-panels::page>
        <div class="flex flex-col gap-4" x-data="{ tab: 'shipments' }">
            <x-filament::tabs label="Content tabs">
                <x-filament::tabs.item @click="tab = 'shipments'" :alpine-active="'tab === \'shipments\''">
                    Shipments
                </x-filament::tabs.item>
                <x-filament::tabs.item @click="tab = 'summary'" :alpine-active="'tab === \'summary\''">
                    Summary
                </x-filament::tabs.item>
            </x-filament::tabs>    
    
            <div>
                <div x-show="tab === 'shipments'" x-cloak>
                    <livewire:intercompany.table-shipment :filters="$filters" />
                </div>
                <div x-show="tab === 'summary'" x-cloak>
                    <livewire:summary-widgets />
                </div>
            </div>
        </div>
    </x-filament-panels::page>
    

By using a Livewire component for the summary section, you can encapsulate the logic and rendering of widgets without duplicating the page structure. This approach allows you to maintain a clean and organized codebase while leveraging the power of Livewire and Filament widgets.

Please or to participate in this conversation.