Filament UI Plus — Enhanced UI components for Filament panels
Enhanced UI components for Filament panels. Adds features that Filament doesn't ship out of the box, designed to be minimally invasive and upgrade-safe.
Add a second, independent sub-navigation to any page (sidebar or tabs) alongside Filament's cluster/resource sub-navigation. Both systems render simultaneously in any position combination.
Place actions (like a back button) to the left of the page heading.
Visual dividers between header actions — vertical line inline, <hr> in dropdowns.
- Smooth collapse/expand width transition for the collapsible sidebar.
- Single rotating chevron replaces Filament's two show/hide buttons.
Bell icon swings on hover.
Automatic skeleton placeholder for tables using deferLoading(). Replaces Filament's default spinner with a realistic table skeleton — header row, body rows with pulsing content bars. Works on any table with deferLoading() enabled, zero configuration needed.
Skeleton placeholder for StatsOverviewWidget during lazy loading. Shows animated stat cards matching the real widget layout while data loads. Card count auto-derives from the widget's $columns property.
- Action column pins to the right edge when tables overflow horizontally.
- Custom scrollbar with trackpad, mouse wheel, and drag support for tables with
overflow-x: clip.
Livewire request progress bar at the top of the viewport.
Tactile shake animation when clicking disabled buttons.
- PHP 8.2+
- Filament 4.x or 5.x
- Laravel 11+
Add the repository to your composer.json:
{
"repositories": [
{
"type": "composer",
"url": "https://filament-ui-plus.composer.sh"
}
]
}Once the repository has been added to the composer.json file, you can install Filament UI Plus like any other composer package using the composer require command:
composer require leek/filament-ui-plusYou will be prompted to provide your username and password.
Loading composer repositories with package information
Authentication required (filament-ui-plus.composer.sh):
Username: [licensee-email]
Password: [license-key]
The username will be your email address and the password will be equal to your license key. Additionally, you will need to append your fingerprint to your license key. For example, let's say we have the following licensee and license activation:
- Contact email: [email protected]
- License key: 8c21df8f-6273-4932-b4ba-8bcc723ef500
- Activation fingerprint: anystack.sh
This will require you to enter the following information when prompted for your credentials:
Loading composer repositories with package information
Authentication required (filament-ui-plus.composer.sh):
Username: [email protected]
Password: 8c21df8f-6273-4932-b4ba-8bcc723ef500:anystack.sh
To clarify, the license key and fingerprint should be separated by a colon (:).
use Leek\FilamentUiPlus\FilamentUiPlusPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentUiPlusPlugin::make())
->sidebarCollapsibleOnDesktop(); // Required for animated sidebar
}php artisan vendor:publish --tag=filament-ui-plus-viewsAdd the plugin's CSS import and @source directives to your panel's theme.css:
/* resources/css/filament/{panel}/theme.css */
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@import '../../../../vendor/leek/filament-ui-plus/resources/css/filament-ui-plus.css';
/* ... your existing @source lines ... */
@source '../../../../resources/views/vendor/filament-panels/**/*.blade.php';
@source '../../../../vendor/leek/filament-ui-plus/resources/views/**/*.blade.php';npm run buildFilamentUiPlusPlugin::make()
->loadingBar(false) // Disable the Livewire loading bar
->defaultBackAction(false) // Disable the automatic back button on HasBeforeHeadingActions pagesAll other features are either opt-in via traits (dual sub-navigation, before-header-actions) or passive CSS/JS that only activates when the relevant DOM elements exist.
Note: Even with
defaultBackAction(false), pages usingHasBeforeHeadingActionscan still render a custom back action by overridinggetBackAction().
Add the HasPageSubNavigation trait to any Filament page and override getPageSubNavigation():
use Leek\FilamentUiPlus\Concerns\HasPageSubNavigation;
use Filament\Navigation\NavigationItem;
use Filament\Pages\Enums\SubNavigationPosition;
class ReportsPage extends Page
{
use HasPageSubNavigation;
public function getPageSubNavigation(): array
{
return [
NavigationItem::make('Funnel Report')
->url(FunnelReportPage::getUrl())
->isActiveWhen(fn () => request()->routeIs(FunnelReportPage::getRouteName())),
NavigationItem::make('Attribution Report')
->url(AttributionReportPage::getUrl())
->isActiveWhen(fn () => request()->routeIs(AttributionReportPage::getRouteName())),
];
}
public function getPageSubNavigationPosition(): SubNavigationPosition
{
return SubNavigationPosition::Start; // Sidebar (default)
// return SubNavigationPosition::Top; // Tabs
// return SubNavigationPosition::End; // Right sidebar
}
}This works completely independently of Filament's cluster/resource sub-navigation. Both systems can render simultaneously in any position combination — both Start, both Top, or any mix.
Add the HasBeforeHeadingActions trait to place actions before the page heading:
use Leek\FilamentUiPlus\Concerns\HasBeforeHeadingActions;
use Filament\Actions\Action;
class ClientDetailPage extends Page
{
use HasBeforeHeadingActions;
// Default: renders a circular back button (history.back())
// Override to customize:
protected function getBackAction(): ?Action
{
return $this->makeDefaultBackAction()
->url(ClientResource::getUrl('index'));
}
}Drop a visual divider between header actions:
use Leek\FilamentUiPlus\Actions\ActionSeparator;
protected function getHeaderActions(): array
{
return [
Action::make('create')->label('New Lead'),
ActionSeparator::make(),
Action::make('export')->label('Export'),
];
}Renders as a vertical 1px line in inline action rows, or an <hr> inside dropdown menus.
Add the HasStatsSkeleton trait to any StatsOverviewWidget subclass:
use Leek\FilamentUiPlus\Concerns\HasStatsSkeleton;
use Filament\Widgets\StatsOverviewWidget;
class RevenueStatsWidget extends StatsOverviewWidget
{
use HasStatsSkeleton;
protected int|array|null $columns = 4;
protected function getStats(): array
{
// ...
}
}The skeleton automatically shows the correct number of placeholder cards based on the widget's $columns property (defaults to 3). Override getPlaceholderStatCount() for custom control:
protected function getPlaceholderStatCount(): int
{
return 6;
}| Feature | Method | View Override? |
|---|---|---|
| Animated Sidebar | Theme CSS | No |
| Sidebar Chevron | View override | Yes (livewire/topbar) |
| Animated Notification Bell | Theme CSS | No |
| Table Horizontal Scroll | JS + Theme CSS | No |
| Table Skeleton Loader | JS + Theme CSS | No |
| Sticky Table Actions | Theme CSS | No |
| Loading Bar | Render hook | No |
| Disabled Button Shake | JS + Theme CSS | No |
| Action Separator | PHP class + Blade | No |
| Stats Overview Skeleton | Trait + Blade + Theme CSS | No |
| Page Sub-Navigation | View override | Yes (page/index) |
| Before Header Actions | View override | Yes (header/index) |
9 of 12 features require zero view overrides and will survive Filament upgrades without changes.
View-override features are clearly marked with [UI Plus] comments for easy diffing when Filament updates.






