Render hooks
Overview
Filament allows you to render Blade content at various points in the frameworks views. It's useful for plugins to be able to inject HTML into the framework. Also, since Filament does not recommend publishing the views due to an increased risk of breaking changes, it's also useful for users.
Registering render hooks
To register render hooks, you can call FilamentView::registerRenderHook()
from a service provider or middleware. The first argument is the name of the render hook, and the second argument is a callback that returns the content to be rendered:
use Filament\Support\Facades\FilamentView;
use Illuminate\Support\Facades\Blade;
FilamentView::registerRenderHook(
'panels::body.start',
fn (): string => Blade::render('@livewire(\'livewire-ui-modal\')'),
);
You could also render view content from a file:
use Filament\Support\Facades\FilamentView;
use Illuminate\Contracts\View\View;
FilamentView::registerRenderHook(
'panels::body.start',
fn (): View => view('impersonation-banner'),
);
Available render hooks
Panel Builder render hooks
panels::auth.login.form.after
- After login formpanels::auth.login.form.before
- Before login formpanels::auth.password-reset.request.form.after
- After password reset request formpanels::auth.password-reset.request.form.before
- Before password reset request formpanels::auth.password-reset.reset.form.after
- After password reset formpanels::auth.password-reset.reset.form.before
- Before password reset formpanels::auth.register.form.after
- After register formpanels::auth.register.form.before
- Before register formpanels::body.end
- Before</body>
panels::body.start
- After<body>
panels::content.end
- After page content, inside<main>
panels::content.start
- Before page content, inside<main>
panels::footer
- Footer of the pagepanels::global-search.after
- After the global search container, inside the topbarpanels::global-search.before
- Before the global search container, inside the topbarpanels::global-search.end
- The end of the global search containerpanels::global-search.start
- The start of the global search containerpanels::head.end
- Before</head>
panels::head.start
- After<head>
panels::page.end
- End of the page content container, also can be scoped to the page or resource classpanels::page.footer-widgets.after
- After the page footer widgets, also can be scoped to the page or resource classpanels::page.footer-widgets.before
- Before the page footer widgets, also can be scoped to the page or resource classpanels::page.header.actions.after
- After the page header actions, also can be scoped to the page or resource classpanels::page.header.actions.before
- Before the page header actions, also can be scoped to the page or resource classpanels::page.header-widgets.after
- After the page header widgets, also can be scoped to the page or resource classpanels::page.header-widgets.before
- Before the page header widgets, also can be scoped to the page or resource classpanels::page.start
- Start of the page content container, also can be scoped to the page or resource classpanels::resource.pages.list-records.table.after
- After the resource table, also can be scoped to the page or resource classpanels::resource.pages.list-records.table.before
- Before the resource table, also can be scoped to the page or resource classpanels::resource.pages.list-records.tabs.end
- The end of the filter tabs (after the last tab), also can be scoped to the page or resource classpanels::resource.pages.list-records.tabs.start
- The start of the filter tabs (before the first tab), also can be scoped to the page or resource classpanels::resource.relation-manager.after
- After the relation manager table, also can be scoped to the page or relation manager classpanels::resource.relation-manager.before
- Before the relation manager table, also can be scoped to the page or relation manager classpanels::scripts.after
- After scripts are definedpanels::scripts.before
- Before scripts are definedpanels::sidebar.nav.end
- In the sidebar, before</nav>
panels::sidebar.nav.start
- In the sidebar, after<nav>
panels::sidebar.footer
- Pinned to the bottom of the sidebar, below the contentpanels::styles.after
- After styles are definedpanels::styles.before
- Before styles are definedpanels::tenant-menu.after
- After the tenant menupanels::tenant-menu.before
- Before the tenant menupanels::topbar.after
- Below the topbarpanels::topbar.before
- Above the topbarpanels::topbar.end
- End of the topbar containerpanels::topbar.start
- Start of the topbar containerpanels::user-menu.after
- After the user menupanels::user-menu.before
- Before the user menupanels::user-menu.profile.after
- After the profile item in the user menupanels::user-menu.profile.before
- Before the profile item in the user menu
Table Builder render hooks
All these render hooks can be scoped to any table Livewire component class. When using the Panel Builder, these classes might be the List or Manage page of a resource, or a relation manager. Table widgets are also Livewire component classes.
tables::toolbar.end
- The end of the toolbartables::toolbar.grouping-selector.after
- After the grouping selectortables::toolbar.grouping-selector.before
- Before the grouping selectortables::toolbar.reorder-trigger.after
- After the reorder triggertables::toolbar.reorder-trigger.before
- Before the reorder triggertables::toolbar.search.after
- After the search containertables::toolbar.search.before
- Before the search containertables::toolbar.start
- The start of the toolbartables::toolbar.toggle-column-trigger.after
- After the toggle columns triggertables::toolbar.toggle-column-trigger.before
- Before the toggle columns trigger
Widgets render hooks
widgets::table-widget.end
- End of the table widget, after the table itself, also can be scoped to the table widget classwidgets::table-widget.start
- Start of the table widget, before the table itself, also can be scoped to the table widget class
Scoping render hooks
Some render hooks can be given a "scope", which allows them to only be output on a specific page or Livewire component. For instance, you might want to register a render hook for just 1 page. To do that, you can pass the class of the page or component as the second argument to registerRenderHook()
:
use Filament\Support\Facades\FilamentView;
use Illuminate\Support\Facades\Blade;
FilamentView::registerRenderHook(
'panels::page.start',
fn (): View => view('warning-banner'),
scopes: \App\Filament\Resources\UserResource\Pages\EditUser::class,
);
You can also pass an array of scopes to register the render hook for:
use Filament\Support\Facades\FilamentView;
FilamentView::registerRenderHook(
'panels::page.start',
fn (): View => view('warning-banner'),
scopes: [
\App\Filament\Resources\UserResource\Pages\CreateUser::class,
\App\Filament\Resources\UserResource\Pages\EditUser::class,
],
);
Some render hooks for the Panel Builder allow you to scope hooks to all pages in a resource:
use Filament\Support\Facades\FilamentView;
FilamentView::registerRenderHook(
'panels::page.start',
fn (): View => view('warning-banner'),
scopes: \App\Filament\Resources\UserResource::class,
);