ashrafic/filament-white-label
White-label your Filament admin panel with ashrafic/filament-white-label. Easily replace Filament branding, logos, colors, and UI labels to deliver a fully customized, client-ready backend experience without touching core files.
Install the plugin and register it on the panel you want to brand:
composer require ashrafic/filament-white-label
php artisan vendor:publish --tag="filament-white-label-config"
php artisan vendor:publish --tag="filament-white-label-views" # optional, for full control
Then, in your PanelProvider:
use Ashrafic\FilamentWhiteLabel\FilamentWhiteLabelPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentWhiteLabelPlugin::make());
}
Where to look first:
config/filament-white-label.php — brand name, logo/favicon paths, colors, and the flags that hide Filament's own branding.resources/views/vendor/filament-white-label — the fastest way to see which markup/CSS hooks you can override.PanelProvider — most behaviour is toggled per panel, not globally.First use case: replace the default Filament logo and name with your client's brand, keep APP_NAME as the source of truth, and hide the "Filament" footer/link for client-facing admin panels. Do this on a single panel first, verify assets resolve, then roll out to other panels.
Per-panel branding. Because registration happens in PanelProvider::panel(), you can give /admin one brand and a customer-facing /app panel another. Keep shared tokens (primary color, support URL) in a small config or settings class and read them inside each provider rather than duplicating literals.
Environment-aware branding. Drive the brand name/logo from env or a config/branding.php file so staging is visually distinct from production. A one-line APP_ENV banner in staging saves a lot of "which environment am I in?" confusion when the UI looks identical everywhere.
Multi-tenant / dynamic branding. If brand assets live in the database (per-tenant logo), resolve them in a service provider or middleware before the panel renders, and avoid caching the resolved model object itself. Cache the scalar values (path, hex color, name) and rehydrate on read — this keeps you clear of serialization issues entirely (see Gotchas).
Custom views instead of config sprawl. Once you need more than a logo swap — custom login layout, footer legal text, an extra nav item — publish the views and edit them. Overriding Blade is more stable across upgrades than stacking config flags.
Asset pipeline. Put logos in public/ (or a disk with a public URL) and reference them with asset(). If you use FilamentAsset/Vite for a custom theme, keep the white-label CSS in the same build so dark mode and the panel's color tokens stay consistent.
Deployment workflow. Treat branding as cache-sensitive. A typical deploy should include:
php artisan vendor:publish --tag="filament-white-label-assets" --force
php artisan filament:optimize-clear
php artisan optimize
Testing. Add a feature test that hits the panel login page and asserts the brand name appears and Filament's default branding does not. That single test catches most regressions after a plugin upgrade.
The v1.0.8 fix — __PHP_Incomplete_Class after upgrade. Earlier versions could unserialize cached data before the relevant class was autoloadable, producing __PHP_Incomplete_Class objects (typically manifesting as an empty/blank panel, a fatal on boot, or a Call to a member function ... on __PHP_Incomplete_Class). v1.0.8 forces the class to load before unserializing. After upgrading, always clear caches — a stale serialized payload from v1.0.7 can still trip you:
php artisan optimize:clear
php artisan filament:optimize-clear
php artisan cache:clear
If a specific environment still fails, identify the cache store holding the payload (php artisan cache:table / your Redis keyspace) and flush the panel/plugin key prefix rather than the whole store.
Never cache objects or closures. The root cause class of bug is worth internalising: anything you put in the cache that contains a plugin instance, a Panel object, or a closure will serialize badly and break on the next deploy or class rename. Cache primitives (strings, arrays of scalars) and rebuild objects on read.
Config caching surprises. php artisan config:cache freezes config/filament-white-label.php. If brand values come from env, changing .env without re-caching appears to do nothing. php artisan config:clear is the fix — remember this before opening an issue.
Published views drift. Once you publish views, --force republishing overwrites your edits. Commit published views to VCS and treat upgrades as a diff review, or keep customisations in your own theme/Blade components layered on top.
Dark mode and favicons. Supply light/dark logo variants and a properly sized favicon set; a single PNG that looks fine on white will vanish on a dark panel. Check both ->darkMode() states before shipping.
Multi-panel cache key collisions. Running two panels with different brands but the same cache prefix can serve the wrong assets. Give each panel a distinct prefix, or key cached brand data by panel ID.
Don't hide all attribution reflexively. Removing Filament branding is a licensing/attribution decision as much as a cosmetic one — confirm what's permitted for your use case, and leave a support/contact link so end users aren't stranded.
Extension points when config isn't enough. Prefer, in order: config → published views → a small custom Blade component registered on the panel → a fork. Reaching for the last option early makes every future release a manual merge.
Version pinning. Pin the plugin ("^1.0") and read the changelog before bumping — cache/serialization fixes like v1.0.8 usually require a cache purge, and skipping that step is the most common post-upgrade failure.
How can I help you explore Laravel packages today?