Laravel Jestream Livewire Theme (Dark/Light mode) Switcher Component
r0073rr0r/laravel-theme-switcher is a Laravel package for laravel jestream livewire theme (dark/light mode) switcher component.
It currently has 1 GitHub stars and 226 downloads on Packagist (latest version v0.1.0).
Install it with composer require r0073rr0r/laravel-theme-switcher.
Discover more Laravel packages by r0073rr0r
or browse all Laravel packages to compare alternatives.
Last updated
A Laravel package for Jetstream and Livewire applications that provides a polished light, dark, and system theme switcher with persistence, package assets, and a Jetstream appearance form.
light, dark, and system modestheme_preference<head> bootstrap script to prevent theme flash before page paintInstall the package via Composer:
composer require r0073rr0r/laravel-theme-switcher
Publish the package config:
php artisan vendor:publish --tag=theme-switcher
Publish the package views if you want to override them:
php artisan vendor:publish --tag=theme-switcher-views
Publish the package translations if you want to customize the text:
php artisan vendor:publish --tag=theme-switcher-translations
Publish the package CSS:
php artisan vendor:publish --tag=theme-switcher-css
Publish the package JavaScript:
php artisan vendor:publish --tag=theme-switcher-assets
Run the migration so the package can persist the user's theme_preference value on the users table:
php artisan migrate
When updating the package, republish the resources you actually use so your application gets the latest views, translations, and frontend files:
composer update r0073rr0r/laravel-theme-switcher
php artisan vendor:publish --tag=theme-switcher-views --force
php artisan vendor:publish --tag=theme-switcher-translations --force
php artisan vendor:publish --tag=theme-switcher-css --force
php artisan vendor:publish --tag=theme-switcher-assets --force
If you have customized any published files, review the changes before overwriting them.
Import the published stylesheet into your application's main stylesheet, for example in resources/css/app.css:
@import './vendor/theme-switcher.css';
If your application uses the package views directly, Tailwind also needs to scan them so utility classes such as h-10, w-10, and rounded-full are generated.
For Tailwind CSS v4, add this to resources/css/app.css:
@source "../../vendor/r0073rr0r/laravel-theme-switcher/resources/views/**/*.blade.php";
If you published the package views instead, point Tailwind to your published copies:
@source "../views/vendor/theme-switcher/**/*.blade.php";
For Tailwind CSS v3, add the same paths to the content array in tailwind.config.js.
Import the published JavaScript into your application's main JS entry file, for example in resources/js/app.js:
import './vendor/theme-switcher';
The package JavaScript expects a global theme manager at window.masonTheme with methods compatible with:
window.masonTheme.getResolvedTheme()
window.masonTheme.applyPreference(preference, { persist: true })
This keeps the Livewire component state synchronized with the browser theme state.
<head>To apply the theme before the page paints, add the package head component inside your main layout <head>, for example in resources/views/layouts/app.blade.php:
<x-theme-switcher-head />
This is the recommended integration point because it renders the inline startup script with the current server-side preference and updates the dark class before the UI flashes.
If you prefer a plain include instead of a Blade component, you can use:
@include('theme-switcher::components.head')
After publishing the package config, you can control the switcher's default behavior without editing package files:
return [
'default_preference' => 'system',
'allowed_preferences' => ['light', 'dark', 'system'],
'cycle_order' => ['light', 'dark', 'system'],
'animations' => [
'enabled' => true,
'duration' => 300,
'icon_transition' => true,
'hover_effects' => true,
'respect_reduced_motion' => true,
],
'persistence' => [
'cookie_enabled' => true,
'cookie_name_preference' => 'theme_preference',
'cookie_name_theme' => 'theme',
'cookie_minutes' => 60 * 24 * 365,
'database_enabled' => true,
],
'ui' => [
'show_system_option' => true,
'button_size' => 'md',
'rounded' => 'full',
'show_tooltip' => true,
],
'events' => [
'dispatch_theme_changed' => true,
'dispatch_preference_updated' => true,
],
];
What these options are for:
default_preference: fallback preference when no authenticated or cookie state exists.allowed_preferences: restrict the package to light, dark, or system.cycle_order: controls the order used by the header toggle button.animations.*: enables or disables hover and icon transitions, with reduced-motion support.persistence.*: decides whether the package writes cookies, updates the authenticated user, or both.ui.*: controls whether system is shown, the button size, shape, and tooltip behavior.events.*: lets you disable the package browser events if you want to manage sync manually.Examples:
['light', 'dark'] removes the system option from the toggle and the profile appearance form.animations.enabled to false renders the same UI without motion transitions.persistence.database_enabled to false keeps the switcher cookie-based only.Render the Livewire component wherever you want the theme toggle button:
<livewire:theme-switcher />
Or:
@livewire('theme-switcher')
The component:
theme-switcher.cycle_orderpersistence configtheme_preference column when database persistence is enabledThe package also registers a Livewire component alias for Jetstream profile settings:
@livewire('profile.update-appearance-form')
If you want to show it on the default Jetstream profile page, open:
resources/views/profile/show.blade.php
Then add this block near the top of the main content area, for example after the profile information form:
<div class="mt-10 sm:mt-0">
@livewire('profile.update-appearance-form')
</div>
<x-section-border />
If you prefer to reference the class directly, you can also use:
@livewire(\r0073rr0r\ThemeSwitcher\Livewire\Profile\UpdateAppearanceForm::class)
The form view rendered by that component comes from the package:
resources/views/profile/update-appearance-form.blade.php
If you publish the package views, you can override that file and adapt it to your own account settings flow.
The package loads its own translations automatically through the theme-switcher namespace, so publishing translations is optional.
Example keys:
__('theme-switcher::theme-switcher.appearance')
__('theme-switcher::theme-switcher.save')
How translation fallback works:
lang/vendor/theme-switcherfallback_localeThis package already includes:
resources/lang/en/theme-switcher.phpresources/lang/sr/theme-switcher.phpThat means a typical application with fallback_locale=en will still show English text even when the active locale has no dedicated theme-switcher translation yet.
After publishing, you can customize these package resources:
resources/views/vendor/theme-switcherlang/vendor/theme-switcherresources/css/vendor/theme-switcher.cssresources/js/vendor/theme-switcher.jsThe startup head script is provided by the package view component:
theme-switcher::components.headtheme-switcher::components.headtheme_preference column if you want per-user persistencetheme-switcher and profile.update-appearance-form Livewire aliasesanimations.respect_reduced_motion is enabled, motion utility classes are reduced for users who prefer less animationThe package test suite is written with Pest and covers configuration helpers, Livewire components, head bootstrap rendering, and persistence behavior.
Run the tests locally with:
php vendor/bin/pest
This package is open-sourced software licensed under the MIT license.
Pull requests are welcome. For larger changes, open an issue first so the scope is clear before implementation.