Filament Render Hooks: 4 Practical Examples

Filament Render Hooks: 4 Practical Examples
Admin
Wednesday, October 4, 2023 7 mins to read
Share
Filament Render Hooks: 4 Practical Examples

Filament has a powerful feature called Render hooks to render Blade content in various places and is especially useful for plugin developers. In this article, we will show you four practical examples of this.


Example 1. Login Page: Add "Login with GitHub" Button

socialite login button

These days, many applications provide an option to authenticate using OAuth via Facebook, GitHub, etc. In this first example, let's see how we can add these login buttons using the render hook.

The render hook can be registered in Service Provider.

app/Providers/AppServiceProvider.php:

use Illuminate\Contracts\View\View;
use Filament\Support\Facades\FilamentView;
 
class AppServiceProvider extends ServiceProvider
{
// ...
 
public function boot(): void
{
FilamentView::registerRenderHook(
'panels::auth.login.form.after',
fn (): View => view('socialite-logins'),
);
}
}

Here, we use the panels::auth.login.form.after render hook and call the socialite-logins View file in which buttons are added.

resources/views/socialite-logins.blade.php:

<x-filament::button
color="gray"
href="https://filamentphp.com"
tag="a"
>
Login using GitHub
</x-filament::button>

And that's it!


Example 2. Language Switcher Menu Plugin

language switcher

The second example comes from a bezhanSalleh/filament-language-switch plugin. This plugin uses the panels::global-search.after render hook and loads the Livewire component.

src/FilamentLanguageSwitchPlugin.php:

class FilamentLanguageSwitchPlugin implements Plugin
{
protected string $renderHookName = 'panels::global-search.after';
 
// ...
 
public function register(Panel $panel): void
{
Livewire::component('switch-filament-language', SwitchFilamentLanguage::class);
 
$panel
->renderHook(
name: $this->getRenderHookName(),
hook: fn (): string => Blade::render('@livewire(\'switch-filament-language\')')
);
}
 
// ...
}

The Blade file package shows a dropdown list of languages and uses the wire:click attribute to make an action.

resources/views/language-switch.blade.php:

// ...
 
<x-filament::dropdown.list class="!border-t-0">
@foreach (config('filament-language-switch.locales') as $key => $locale)
@if (!app()->isLocale($key))
<button type="button" class="fi-dropdown-list-item flex w-full items-center gap-2 whitespace-nowrap rounded-md p-2 text-sm transition-colors duration-75 outline-none disabled:pointer-events-none disabled:opacity-70 fi-dropdown-list-item-color-gray hover:bg-gray-950/5 focus:bg-gray-950/5 dark:hover:bg-white/5 dark:focus:bg-white/5" wire:click="changeLocale('{{ $key }}')">
 
@if (config('filament-language-switch.flag'))
<span>
<x-dynamic-component :component="'flag-1x1-' . (!blank($locale['flag_code']) ? $locale['flag_code'] : 'un')"
class="flex-shrink-0 w-5 h-5 group-hover:text-white group-focus:text-white text-primary-500"
style="border-radius: 0.25rem" />
</span>
@else
<span
class="w-6 h-6 flex items-center justify-center flex-shrink-0 @if (!app()->isLocale($key)) group-hover:bg-white group-hover:text-primary-600 group-hover:border group-hover:border-primary-500/10 group-focus:text-white @endif bg-primary-500/10 text-primary-500 font-semibold rounded-full p-4 text-xs">
{{ \Illuminate\Support\Str::of($locale['name'])->snake()->upper()->explode('_')->map(function ($string) use ($locale) {
return \Illuminate\Support\Str::of($locale['name'])->wordCount() > 1 ? \Illuminate\Support\Str::substr($string, 0, 1) : \Illuminate\Support\Str::substr($string, 0, 2);
})->take(2)->implode('') }}
</span>
@endif
<span class="hover:bg-transparent text-gray-700 dark:text-gray-200">
{{ \Illuminate\Support\Str::of($locale[config('filament-language-switch.native') ? 'native' : 'name'])->headline() }}
</span>
</button>
@endif
@endforeach
 
</x-filament::dropdown.list>
 
// ...

Example 3. Adding Alert Notification On Top of Page

scoped render hook

For the third example, let's see how we can scope the render hook to a specific resource or page. You can find the list of which hooks can be scoped in the official documentation.

app/Providers/AppServiceProvider.php:

use Illuminate\Contracts\View\View;
use Filament\Support\Facades\FilamentView;
 
class AppServiceProvider extends ServiceProvider
{
// ...
 
public function boot(): void
{
FilamentView::registerRenderHook(
'panels::page.start',
fn (): View => view('warning-banner'),
scopes: \App\Filament\Resources\OrderResource::class,
);
}
}

In this example, we use the panels::page.start render hook to call a warning-banner View file and scope it only to an OrderResource resource.

We can add everything that needs to be shown inside the Blade file.

resources/views/warning-banner.blade.php:

<div class="mt-3 px-4 py-2 bg-primary-500/10 text-danger-600">
Sensitive orders.
</div>

Now, when we visit any page belonging to an OrderResource, we will see this message.


Example 4. Add User Avatar/Button on the Bottom

sidebar footer

In this example, we will add a user's avatar with a name and a sign-out button at the bottom of the sidebar.

app/Providers/AppServiceProvider.php:

use Illuminate\Contracts\View\View;
use Filament\Support\Facades\FilamentView;
 
class AppServiceProvider extends ServiceProvider
{
// ...
 
public function boot(): void
{
FilamentView::registerRenderHook(
'panels::sidebar.footer',
fn (): View => view('sidebar-footer'),
);
}
}

We are using the panels::sidebar.footer render hook for this. When styling this part, if we don't make it fixed, then it will be added just after the navigation.

not fixed sidebar

But if we make it fixed and set it at the bottom, the result will be expected:

sidebar footer

In this case, the Blade file would look like this:

resources/views/sidebar-footer.blade.php:

@php
$user = filament()->auth()->user();
@endphp
 
<div class="bottom-0 left-0 z-20 w-full p-4 bg-white border-t border-gray-200 md:flex md:items-center md:justify-between md:p-6 dark:bg-gray-800 dark:border-gray-600">
<x-filament::avatar
:src="filament()->getUserAvatarUrl($user)"
class="fi-user-avatar rounded-full"
style="margin-right: 1rem;"
/>
 
<div class="space-y-1">
<div class="text-gray-700 dark:text-gray-200 font-medium text-sm">
{{ filament()->getUserName($user) }}
</div>
<form
action="{{ filament()->getLogoutUrl() }}"
method="post"
class="my-auto -me-2.5 sm:me-0"
>
@csrf
 
<x-filament::button
color="gray"
icon="heroicon-m-arrow-left-on-rectangle"
icon-alias="panels::widgets.account.logout-button"
labeled-from="sm"
tag="a"
type="submit"
size="xs"
outlined
>
{{ __('filament-panels::widgets/account-widget.actions.logout.label') }}
</x-filament::button>
</form>
</div>
</div>

You can find all Filament render hooks in the official documentation.


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