Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Themes Laravel Package

3x1io/filament-themes

A Filament package for quickly adding theme customization to your admin panels, with ready-made color themes and dark mode support. Configure themes in your panel provider to restyle the UI without writing custom CSS, keeping Filament's look consistent and easy to tweak.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish the package assets:

composer require 3x1io/filament-themes
php artisan vendor:publish --tag="filament-themes-config"
php artisan vendor:publish --tag="filament-themes-migrations"
php artisan migrate

Register the plugin with your Filament panel (check the package README for the exact plugin class name and namespace — older 3x1io packages use Threex1io\..., newer ones may use a different vendor namespace):

use Threex1io\FilamentThemes\FilamentThemesPlugin;

public function panel(Panel $panel): Panel
{
    return $panel->plugins([
        FilamentThemesPlugin::make(),
    ]);
}

Where to look first, in this order:

  1. config/filament-themes.php — table name, model binding, resource visibility, upload paths.
  2. The published migration and Theme model — understand the columns (name, key/slug, path/view folder, is_active, possibly user_id) since you will query this table directly for frontend resolution.
  3. The Filament resource class — this is what your admins actually touch; it also shows how state (active theme) is persisted.
  4. The helper/facade or ThemeManager service — the package usually exposes a single entry point like theme() or themes()->getActive(). Confirm the actual API before designing around it.

First use case: create a theme record from the Filament admin (e.g. key default), add a matching view folder such as resources/views/themes/default/, activate it, then render a page from your frontend controller using that theme's path instead of hardcoding:

$theme = \Threex1io\FilamentThemes\Models\Theme::where('is_active', true)->firstOrFail();

return view("themes.{$theme->key}.welcome");

That end-to-end loop — admin record → view folder → resolved view — is the whole package in one pass; get it working before adding middleware or per-user overrides.

Implementation Patterns

Seed the theme registry instead of clicking it into production. Treat themes as deployable config. Create a seeder with idempotent updateOrCreate() on the theme key so every environment (dev, staging, CI) has the same rows without manual admin steps:

Theme::updateOrCreate(
    ['key' => 'default'],
    ['name' => 'Default Theme', 'path' => 'themes/default', 'is_active' => true]
);

Resolve the active theme once per request, via middleware. Doing a DB query per Blade view is the most common performance mistake with this package. Resolve in middleware, cache the result, and share it:

class ResolveTheme
{
    public function handle($request, Closure $next)
    {
        $theme = Cache::rememberForever('filament-themes.active', fn () =>
            Theme::where('is_active', true)->first()
        );

        view()->share('theme', $theme);

        return $next($request);
    }
}

Invalidate that cache key from a model observer on saved/deleted, or from the Filament resource's afterSave() hook, so switching themes in the admin panel doesn't require a deploy or a manual cache:clear.

Use a view composer or layout helper for view resolution. Don't repeat "themes.{$theme->key}.page" everywhere. Define a helper that falls back to a default theme when the folder or view is missing:

function theme_view(string $name, array $data = [])
{
    $theme = app('theme') ?? Theme::default();

    return view()->exists("themes.{$theme->key}.{$name}")
        ? view("themes.{$theme->key}.{$name}", $data)
        : view("themes.default.{$name}", $data);
}

Extend the resource rather than editing vendor files. Add preview images, a color palette, a Vite entry name, or a "live preview" link by subclassing the resource or using resource extension hooks. Register it in the panel with a navigation group (->navigationGroup('Appearance')) and gate it behind a policy so only admins can switch themes.

Treat assets per theme explicitly. If each theme ships its own CSS/JS, either configure a separate Vite entry per theme or serve compiled files from public/themes/{key}. Filament's own assets are unrelated — confirm the package doesn't try to touch the admin panel's styling, because "FrontEnd Themes Manager" means frontend Blade views, not panel theming.

Use a session-scoped override for previews. Keep the persisted active theme as the default, then let /preview/{key} set session(['theme_preview' => $key]) and have your middleware prefer that key. This gives you a safe preview workflow without letting editors accidentally publish an unfinished theme.

Testing pattern: use RefreshDatabase, a ThemeFactory, and assert the rendered view name rather than full HTML:

$this->get('/')->assertViewIs('themes.default.welcome');

Cover the fallback path (active theme folder deleted) — that's the case that breaks in production, not the happy path.

Gotchas and Tips

  • Vendor namespace moved. Older 3x1io packages use Threex1io\...; newer ones may use a different namespace. If FilamentThemesPlugin isn't found, run composer show 3x1io/filament-themes and inspect the package's src/ or its composer.json autoload section before guessing the import.
  • Publish tags vary by release. If --tag="filament-themes-migrations" returns nothing, run php artisan vendor:publish without a tag and pick the provider interactively; tags are easy to rename between minor versions.
  • Last release is April 2024. Pin the version in composer.json and check the repo's issue tracker before upgrading Filament or Laravel. Filament v3 plugin signatures are not forward-compatible with v4 — test the constraint rather than assuming ^3.0 is safe.
  • No cache invalidation out of the box. The package stores the active flag in the database but won't clear your cache. If you cache the active theme (you should), wire invalidation into the model observer — otherwise "I switched the theme and nothing happened" becomes a recurring bug report.
  • Missing theme folders cause 500s, not 404s. Always implement the fallback branch shown above. A deleted view directory after an admin clicks "delete theme" is the single most likely production incident with any theme manager.
  • Authorization is your job. Publish the policy or gate the resource; a theme switcher is effectively a styling-deploy button. Also hide the resource from non-admin panels with ->visible(fn () => auth()->user()->isAdmin()).
  • Config cache quirks. After changing config/filament-themes.php, run php artisan config:clear. In CI, view:cache and route:cache will bake in whichever theme folders existed at build time — deploy theme files before running the optimizer, or don't run view:cache for theme views.
  • Multiple Filament panels. If you have both an admin and a user panel, register the plugin only where it belongs; the resource otherwise appears in every panel that shares the plugin list.
  • Don't store user-chosen themes in the same is_active column if the package supports per-user themes — read the migration carefully. Global active theme and per-user preference are different concepts, and conflating them causes "one user switched everyone's theme" bugs.
  • Publish, then extend. Copy the resource and config into app/ via published stubs rather than editing vendor/; the package is MIT-licensed but vendor edits vanish on the next composer update.
  • Star count of 37 means the ecosystem is small — budget time to read the source (~a few hundred lines) rather than relying on docs. The migration, resource, and one helper file are usually the entire package.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console