jeremykenedy/laravel-darkmode-toggle
jeremykenedy/laravel-darkmode-toggle provides a simple, ready-to-use dark mode toggle for Laravel applications. Add a Blade component, configure its appearance, and let users switch between light and dark themes with their preference persisted across visits. Lightweight and easy to integrate.
prefers-color-scheme, cross-tab sync, ARIA semantics, and per-framework markup add up to real engineering time plus a permanent maintenance tail. This package reduces that to a config block and a Blade / Livewire / Vue / React / Svelte component.aria-haspopup, aria-expanded, role="menu", role="menuitemradio" with aria-checked, Escape-to-close with focus returned to the trigger, ArrowUp/ArrowDown navigation, visible focus styles, and aria-hidden icons so screen readers read the label rather than the glyph. That is a shippable response to an audit finding or a WCAG 2.1 AA commitment without a bespoke component build.resources/lang/en/darkmode.php shipped unused. Localized dark mode copy becomes a translation task, not a code change.persist_field (it previously read a hardcoded dark_mode column) and the Livewire toggle respects persist_to_server. "Remember my theme across devices" becomes a supported use case rather than a broken one.color_scheme option mirrors the theme onto the CSS color-scheme property so form controls and scrollbars match — a small but visible quality signal.Adopt when:
Look elsewhere or wait when:
prefers-color-scheme media query plus a few CSS custom properties genuinely covers your need; adding a dependency and a JS bundle is a bad trade for that.Caveats to state plainly:
data_attribute, color_scheme and sync_across_tabs all ship off. Upgrading changes nothing — and delivers nothing — until you turn them on. Budget the configuration work as part of the upgrade, not after it.composer.json still permits Laravel 10/11 to avoid cutting off existing installs, but Composer will not resolve them. Read the requirements, not the constraint string.To executives: This is a small, well-maintained dependency that closes a real accessibility gap and eliminates a recurring class of bug — dark mode that flickers, doesn't stick, or breaks on one page. It ships an ARIA-compliant menu button on every framework we might use, instead of one we would build and maintain ourselves. The release also forces a question we need to answer anyway: Laravel 10 and 11 carry an unpatched CVE, and this package now effectively requires Laravel 12/13. That framework upgrade is the real project; the package upgrade is a side effect and is backwards compatible once we are there. The ask is to sequence the package bump inside the Laravel 12/13 workstream and decide whether to enable the three new opt-in options this cycle or next.
To engineering: v2.0.0 is a low-risk upgrade. Every config key, class name, public property, Blade component alias, view name, publish tag and command signature is unchanged; all new config ships off by default; and a backwards-compatibility contract test now pins the public API. The changelog is mostly fixes to things that were quietly broken: the Vue component used a v-click-outside directive that was never defined and threw on mount, React/Vue/Svelte didn't follow prefers-color-scheme changes in System mode, unguarded localStorage threw on page load, an empty class_name emitted classList.toggle(''), a stored preference outside light/dark/system painted one theme then switched to another, the toggle read a hardcoded column rather than persist_field, the Livewire toggle ignored persist_to_server and sync_across_tabs, darkmode:switch and darkmode:update reported success without changing anything when DARKMODE_CSS/DARKMODE_FRONTEND were set, .env matching was a substring check, and darkmode:install --css=material --no-interaction wrote an unsupported framework. The darkmode-js publish tag now exists, so the Vue/React/Svelte components actually land at the import path the README documents. Tests went from 105 to 355, and CI gained PHPStan level 6, composer validate --strict, composer audit, a real frontend compile job, and PHP 8.5 in the matrix.
How can I help you explore Laravel packages today?