jeremykenedy / laravel-darkmode-toggle
A standalone dark mode toggle component for Laravel with multi-framework support (Tailwind, Bootstrap 5, Bootstrap 4) and multiple frontend options (Blade, Livewire, Vue, React, Svelte).
Package info
github.com/jeremykenedy/laravel-darkmode-toggle
pkg:composer/jeremykenedy/laravel-darkmode-toggle
Requires
- php: ^8.2|^8.3
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- illuminate/view: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- pestphp/pest: ^2.0|^3.0|^4.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0|^4.0
This package is auto-updated.
Last update: 2026-04-02 10:26:04 UTC
README
A standalone dark mode toggle component for Laravel with Light, Dark, and System modes,
localStorage persistence, optional server-side sync, and full CSS/frontend framework parity.
Table of Contents
- Framework Support
- Requirements
- Installation
- Quick Start
- Features
- Configuration
- Server-Side Persistence
- Changing Frameworks
- Artisan Commands
- How It Works
- Testing
- License
Framework Support
Every CSS and frontend combination is fully supported with identical features:
| Blade + Alpine.js | Livewire 3 | Vue 3 | React 18 | Svelte 4 | |
|---|---|---|---|---|---|
| Tailwind v4 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Bootstrap 5 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Bootstrap 4 | ✅ | ✅ | ✅ | ✅ | ✅ |
15 combinations. Zero feature gaps.
Requirements
- PHP 8.2+
- Laravel 12 or 13
- One CSS framework: Tailwind v4, Bootstrap 5, or Bootstrap 4
- One frontend: Blade + Alpine.js, Livewire 3, Vue 3, React 18, or Svelte 4
Installation
composer require jeremykenedy/laravel-darkmode-toggle php artisan darkmode:install
The interactive installer will prompt you to select your CSS and frontend frameworks.
Non-Interactive Install
php artisan darkmode:install --css=tailwind --frontend=blade
Note: If the package is already installed, the install command will warn you and recommend using
darkmode:updateinstead. You can force a fresh reinstall with--force, but this will overwrite your config and published views.
Quick Start
1. Add the init script to <head>
Prevents flash of wrong theme on page load:
<head> @include('darkmode::init-script') </head>
2. Add the toggle component
Blade (with Alpine.js):
<x-darkmode-toggle />
Livewire:
<livewire:darkmode-toggle />
Vue:
<script setup> import DarkmodeToggle from './vendor/darkmode-toggle/DarkmodeToggle.vue' </script> <template> <DarkmodeToggle persist-url="/darkmode/preference" /> </template>
React:
import DarkmodeToggle from './vendor/darkmode-toggle/DarkmodeToggle' export default function Nav() { return <DarkmodeToggle persistUrl="/darkmode/preference" /> }
Svelte:
<script> import DarkmodeToggle from './vendor/darkmode-toggle/DarkmodeToggle.svelte' </script> <DarkmodeToggle persistUrl="/darkmode/preference" />
Features
- Three modes: Light, Dark, System (follows OS preference)
- Instant switching: Persists to
localStorage, no page reload - FOUC prevention: Init script runs synchronously in
<head>before paint - Server-side sync: Optionally saves preference to user profile via PUT/POST
- Class-based: Adds/removes
darkclass on<html>element - System tracking: Listens for OS preference changes in real time
- Configurable: Every aspect via
config/darkmode.phpand ENV variables
Configuration
php artisan vendor:publish --tag=darkmode-config
Key options in config/darkmode.php:
| Option | Default | Description |
|---|---|---|
strategy |
class |
Dark mode strategy |
class_name |
dark |
Class added to <html> |
default |
system |
Default mode (light/dark/system) |
storage_key |
theme |
localStorage key |
persist_to_server |
true |
Save to DB when authenticated |
persist_route |
/profile/dark-mode |
Server persistence endpoint |
persist_method |
PUT |
HTTP method for persistence |
persist_field |
dark_mode |
Request/DB field name |
css_framework |
null |
null = inherit from ui-kit.css_framework |
Server-Side Persistence
The package includes a route PUT /darkmode/preference that saves the preference to the user's profile. To use your own route:
'persist_route' => '/profile/dark-mode', 'routes' => ['enabled' => false],
The toggle sends a JSON request:
{ "dark_mode": "dark" }
Changing Frameworks
After initial installation, use the update or switch commands to change your CSS or frontend framework without losing your configuration.
Update (Interactive)
The update command shows the same stepped prompts as the installer, letting you walk through framework selection:
php artisan darkmode:update
Or pass options directly:
php artisan darkmode:update --css=bootstrap5 php artisan darkmode:update --frontend=vue php artisan darkmode:update --css=tailwind --frontend=livewire
Switch (Quick)
The switch command is a shorthand for changing one or both frameworks in a single command:
php artisan darkmode:switch --css=bootstrap5 php artisan darkmode:switch --frontend=livewire php artisan darkmode:switch --css=tailwind --frontend=vue
Both commands update your .env file and clear the config/view caches. After switching, run:
npm run build
Artisan Commands
| Command | Description |
|---|---|
darkmode:install |
Fresh install with interactive prompts. Detects existing installation and warns before overwriting. |
darkmode:update |
Update framework selection with interactive prompts. Safe, does not overwrite config. |
darkmode:switch |
Quick framework switch via flags. --css and/or --frontend required. |
Install Options
| Flag | Description |
|---|---|
--css= |
CSS framework: tailwind, bootstrap5, bootstrap4 |
--frontend= |
Frontend: blade, livewire, vue, react, svelte |
--force |
Skip reinstall confirmation when already installed |
How It Works
- Init script runs synchronously in
<head>, readslocalStorage, addsdarkclass before paint - Toggle component renders sun/moon/monitor icons with dropdown for Light/Dark/System
- On selection: updates
localStorage, toggles HTML class, optionally PUTs to server - System mode: listens for
prefers-color-schememedia query changes in real time
Testing
./vendor/bin/pest --ci
License
This package is open-sourced software licensed under the MIT license.