Integrating Flux Components in a Laravel Filament App: The Key to Fixing Script Loading Issues
Livewire Flux and Filament
Livewire Flux is an amazingly crafted component library that is built on top of Livewire. It contains a wide range of components that almost cover all the needs of a modern web application. The components are fully interactive and equipped with the necessary Alpine.js code to make them work. Flux adapts Tailwind CSS as its UI library, which makes it compatible with almost every Laravel project.
Filament is a powerful and flexible Laravel package that allows you to build beautiful, feature-rich, and fully customizable admin panels. Filament is built on top of Livewire, so it's a perfect match for Livewire Flux. But integrating Flux components into a Filament app is not straightforward as you might expect. Let's get closer to the issue and see how we can fix it.
The Problem
In my Filament project, I needed to create a custom page called Calendar View. This page contains a calendar component that displays events on a monthly basis, and there is a dropdown to select the month. This page should be part of an existing resource called Bookings.
I have followed the instructions in the Filament documentation to create a custom page.
The page is created successfully and I can access it via the URL /admin/bookings/calendar
Installing Flux
The installation process for flux is simple and straightforward.
After installing flux via composer and activate your license, you have to add both @fluxStyles
and @fluxScripts
to your layout file.
<head>
...
@fluxStyles
</head>
<body>
...
@fluxScripts
</body>
Then after, you'll have to setup Tailwind CSS which is a requirement for Flux to work. But let's not get into that now.
Trying Flux Components
At this stage, you should be questioning what layout file filament uses by default.
I had an app.blade.php
file in the resources/views/components/layouts/
directory. I gave it a shot to add the @fluxStyles
and @fluxScripts
to it and navigate to the calendar view page where I added a simple heading, subheading and a select (dropdown) component.
<x-filament-panels::page>
<div class="flex flex-col space-y-4">
<div class="flex flex-col space-y-2">
<h1 class="text-2xl font-bold">Booking Calendar</h1>
<p>Events are displayed based on the selected month</p>
</div>
<div class="flex flex-col space-y-2">
<x-flux::select placeholder="Choose month...">
<x-flux::option value="asd">January</x-flux::option>
<x-flux::option value="asd1">February</x-flux::option>
.....
<x-flux::option value="asd4">November</x-flux::option>
<x-flux::option value="asd4">December</x-flux::option>
</x-flux::select>
</div>
</div>
</x-filament-panels::page>
As you can see from the screenshot below, the dropdown for selecting the month is there and all of the options are visible. which is great!
The Problem
Now I want the dropdown to be searchable, so I picked this option as per the Flux documentation and now the whole dropdown is no longer working.
<x-flux::select placeholder="Choose month..." searchable variant="listbox>
.....
If you take a look at the screenshot below, you will see that the select options are not rendered. But why the simple select is working? Cause the options are native and does not require any JavaScript to render them.
So the problem is that Flux styles and scripts are not being loaded correctly!
A simple test that validates this is to delete the content of the
app.blade.php
file and navigate to the calendar view page. You will see that there is no change. So that's for sure the wrong base layout to install flux in!
The Solution
In order to fix the issue, we have to find out what layout file filament uses by default and add the Flux styles and scripts to it.
Digging into the filament code, we can find that the layout file is base.blade.php
in the vendor/filament/filament/resources/views/components/layout/
directory.
There are two ways to add the Flux styles and scripts to the layout file:
-
Manually copy the file from the vendor directory to the
resources/views/vendor/filament/components/layouts/base.blade.php
directory and add the@fluxStyles
and@fluxScripts
to it. This will basically tell the Blade engine to look for the layout file in theresources/views/vendor/filament/components/layouts/
directory first before looking for it in thevendor
directory. But this is not a good idea because every time you upgrade filament, you will have to merge the new changes with the modified file. -
Use Filament's layout render hooks to add the Flux styles and scripts to the layout file. Filament has an option to render custom content at specific points within the framework views. This is done using the
FilamentView::registerRenderHook
method. You can check the Filament documentation for more information.
Looking deeper into the base.blade.php
file, there are two interesting lines there:
<html>
....
<head>
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::HEAD_START, scopes: $livewire->getRenderHookScopes()) }}
.....
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::HEAD_END, scopes: $livewire->getRenderHookScopes()) }}
</head>
....
<body>
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::BODY_START, scopes: $livewire->getRenderHookScopes()) }}
.....
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::BODY_END, scopes: $livewire->getRenderHookScopes()) }}
</body>
</html>
Which means that we can add the Flux styles and scripts to the HEAD_END
and BODY_END
render hooks.
How to do that?
1- Create a view file called flux-scripts.blade.php
in the resources/views/flux/
directory and add the following code to it:
php artisan make:view flux/flux-scripts
add the following line to it:
@fluxScripts
2- Create a view file called flux-styles.blade.php
in the resources/views/flux/
directory and add the following code to it:
php artisan make:view flux/flux-styles
add the following line to it:
@fluxStyles
3- Register required render hooks
Now, lets navigate to the AppServiceProvider.php
file in the app/Providers
directory and register the required hooks by adding the following code to the boot
method:
public function boot(): void
{
....
FilamentView::registerRenderHook(
PanelsRenderHook::BODY_END,
fn (): View => view('flux.flux-scripts')
);
FilamentView::registerRenderHook(
PanelsRenderHook::HEAD_END,
fn (): View => view('flux.flux-styles')
);
....
}
We should be done now!
Navigate to the calendar view page and you will see that the dropdown is now searchable and the options are rendered correctly.
I hope this article helps you to integrate Flux components into your Filament app without any issues. Please let me know if you have any questions or feedback.
Happy coding!