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

Theme Support Livewire Laravel Package

liberusoftware/theme-support-livewire

Livewire bindings for Liberu's theme support package, helping Laravel apps build dynamic, theme-aware interfaces. Keeps Livewire components in sync with the active theme, so users can switch themes without losing state—ideal for dashboards and settings UIs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path from install to a working theme switcher:

  1. Install both packages. This is a presentation adapter, so it depends on liberusoftware/theme-support for the actual theme resolution, registry, and asset wiring. Install the parent first, then the adapter:

    composer require liberusoftware/theme-support liberusoftware/theme-support-livewire
    
  2. Look at the service provider first. Open vendor/liberusoftware/theme-support-livewire/src/ and read the provider's boot() and register() methods. That tells you:

    • Whether the Livewire component is auto-registered or must be published/aliased.
    • Whether there's a config file to publish (php artisan vendor:publish --tag=theme-support-livewire-config).
    • Whether views are publishable (you'll almost certainly want to override the switcher markup).
  3. Confirm the Livewire component class. The package's whole job is a presentation adapter, so there should be a single component (something like ThemeSwitcher or ThemeSelector) that wraps the parent package's theme-setting API. Find its render() method and its public properties — those are your contract.

  4. Publish views (recommended). You'll want to style the switcher, so publish and edit rather than relying on the vendor Blade:

    php artisan vendor:publish --tag=theme-support-livewire-views
    
  5. First use case: drop it in the layout. Typical first integration is a header dropdown:

    {{-- resources/views/layouts/app.blade.php --}}
    <header>
        ...
        <livewire:theme-switcher />
    </header>
    

    If the tag doesn't resolve, check the provider for a custom component alias (e.g. theme-switcher vs theme-support-livewire.switcher).

  6. Verify persistence. Switch the theme, then reload the page. If the theme resets, the adapter is changing the in-memory theme but the parent package isn't persisting it — see the Gotchas section.

The first genuinely useful scenario is almost always: authenticated user with a theme preference stored on their profile, plus a session/cookie fallback for guests. Build that one flow end-to-end before adding anything else.

Implementation Patterns

1. Layout-level switcher (the default pattern). Render the component once in your base layout. Because Livewire re-renders only the component, a theme change will not reload the page by default — you need the switcher to force a full navigation or a client-side theme swap. The cleanest pattern is a wire:click handler in the component that sets the theme and then dispatches a browser event your JS listens to:

// in your published component
public function setTheme(string $theme): void
{
    $this->themeManager->set($theme);   // parent package API
    $this->dispatch('theme-changed', theme: $theme);
}
// resources/js/app.js
Livewire.on('theme-changed', ({ theme }) => {
    document.documentElement.dataset.theme = theme;
});

Pair this with CSS custom properties ([data-theme="dark"] { --bg: ...; }) so you never need a round trip to re-style the page.

2. Server-rendered <html> attribute (avoids flash of wrong theme). Set the theme attribute in the layout, not in JS, so the first paint is correct:

<html data-theme="{{ app(\Liberu\Theme\Support\ThemeManager::class)->current() }}">

Then the Livewire switcher only needs to update the DOM after the fact. This is the pattern to prefer for anything user-facing.

3. User-preference persistence. Wrap the parent package's setter in a small action so you keep the adapter thin:

public function setTheme(string $theme): void
{
    abort_unless(array_key_exists($theme, config('theme-support.themes')), 422);

    auth()->user()?->update(['theme' => $theme]);
    session(['theme' => $theme]);
    app(ThemeManager::class)->set($theme);

    $this->dispatch('theme-changed', theme: $theme);
}

Resolve precedence (user → session → config default) in a middleware or a ThemeManager decorator, not in the Livewire component. The component should stay dumb.

4. Middleware for consistent resolution.

// app/Http/Middleware/ApplyUserTheme.php
public function handle($request, Closure $next)
{
    $theme = $request->user()?->theme
        ?? $request->session()->get('theme')
        ?? config('theme-support.default');

    app(ThemeManager::class)->set($theme);

    return $next($request);
}

Register globally (or in web) so every request — including Livewire polling requests — sees the same theme. Without this, a Livewire update request can resolve a different theme than the initial page load.

5. Testing pattern. Livewire tests are the fastest way to lock down the switcher contract:

Livewire::test(ThemeSwitcher::class)
    ->call('setTheme', 'dark')
    ->assertDispatched('theme-changed', theme: 'dark')
    ->assertSet('current', 'dark');

Add an assertion that an unknown theme is rejected, otherwise you have an easy injection point for arbitrary CSS class names.

Gotchas and Tips

  • This package does not resolve themes. It is an adapter. All registry, validation, asset, and default-theme logic lives in liberusoftware/theme-support. When something is wrong, debug the parent first — the adapter is likely a thin wrapper.

  • Livewire request lifecycle vs. theme middleware. This is the single most common bug with adapters like this. If your theme middleware runs on web but not on Livewire's update endpoint (or vice-versa), the component's rendered data-theme can disagree with the page. Apply the middleware globally, and assert the theme inside the component's mount() if you need certainty.

  • Zero dependents, zero stars. Treat the public API as unstable. Pin to a specific version in composer.json ("liberusoftware/theme-support-livewire": "0.x.y" rather than ^0.x) and keep a fallback in your own code — e.g. don't call ThemeManager directly everywhere, wrap it in one service class so you can replace the adapter if the package stalls.

  • Check Livewire version compatibility. Livewire 3 changed dispatchBrowserEvent → dispatch and the component registration API; an older adapter will silently fail on Livewire 3 (events simply won't fire). Read the adapter's composer.json require block for livewire/livewire before adopting.

  • Cache-busting on theme assets. If themes ship their own CSS, the parent package usually registers asset paths. After publishing, php artisan view:clear and php artisan cache:clear — cached compiled views will happily serve the old theme's markup for hours.

  • Validation is your job. A theme name often becomes a directory or a CSS class. Validate against config('theme-support.themes') (or the parent's registry) before calling the setter; never trust a raw Livewire public property that can be mutated client-side. Public properties in Livewire components are user-controllable.

  • wire:model on a theme selector is tempting but wrong for this use case. A wire:model.live select will trigger a request per keystroke and may race with the theme-changed event. Use wire:change with an explicit call('setTheme', ...) or a button group — deterministic is better than reactive here.

  • Extension point: publish and override. Almost everything in a presentation adapter is designed to be published. Views, config, and sometimes the component class itself are publishable. Prefer overriding the Blade view over subclassing the component — subclassing breaks if the package renames the class in a patch release.

  • Debugging checklist when the theme won't switch. In order: (1) Livewire request hits your middleware? (2) Component dispatches the event? (3) Browser listener attached before the first Livewire message? (4) Session cookie actually persisted? (5) The <html> attribute changed but CSS variables didn't load for the new theme? Each of these fails silently and looks identical from the UI.

  • Keep the switcher unauthenticated-safe. Guests should be able to switch themes via session. If the component calls auth()->user()->update(...) unconditionally, you get a Call to a member function on null on any public page. Guard the persistence, not the switching.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo