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

Dark Mode Laravel Package

laravel-ux/dark-mode

Add dark mode to Laravel apps with a simple toggle UI and persistent user preference. laravel-ux/dark-mode offers a lightweight, Blade-friendly setup for theme switching, helping you deliver comfortable light and dark experiences without custom JavaScript.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. v0.1.0 is a narrowly scoped presentation-layer package: it owns the root dark class, a session-persisted Livewire toggle, an Alpine store bridge, and a browser event contract (dark-mode-toggled). That is a clean fit for Laravel apps already standardized on Blade + Livewire + Alpine + Tailwind's darkMode: 'class' strategy. It is a poor fit for apps using CSS prefers-color-scheme-only theming, non-Tailwind CSS stacks, or Vue/React frontends. The package deliberately spans three state channels — server session, Alpine store, and DOM class — which is the correct design for Livewire apps but makes it a cross-cutting concern rather than a drop-in widget.

Integration feasibility. High for greenfield Laravel apps: one Blade directive in the layout, one component in the nav, and a Tailwind config flag. The @darkModeScripts directive is the load-bearing piece — it must render before first paint to avoid a theme flash, which means placement in <head> relative to Livewire/Alpine script tags is an integration constraint, not a detail. Retrofitting into an app with an existing hand-rolled dark mode is materially harder: two writers to the same dark class and two listeners on the same storage key will fight, and the session-backed state may disagree with localStorage.

Technical risk. Moderate, concentrated in four areas:

  • Pre-1.0 API surface. v0.1.0 implies breaking changes in minor releases. The directive name, component alias ux.dark-mode::toggle, event name, and store key are all public contract with no stability guarantee.
  • First-paint correctness. Session-persisted state means the initial class may be server-derived; if the inline script is late, blocked by CSP, or skipped by a full-page cache, users get a flash or the wrong theme.
  • State reconciliation. Three channels plus wire:navigate soft reloads create plausible desync paths (Alpine store reinitializing on navigate, session write racing the DOM toggle, cross-tab drift).
  • Dependency breadth. It pulls in Livewire, Alpine, and the Laravel UX UI/Icons components — each an independent upgrade vector on a package that is itself at 0.1.x.

Key questions.

  1. Does @darkModeScripts emit a blocking inline script safe for first paint, and is it CSP-nonce aware?
  2. Is the dark class server-rendered from session, client-rendered, or both? This determines full-page-cache viability and cache-vary requirements.
  3. What happens on wire:navigate — does the Alpine store and toggle state survive, or reinitialize?
  4. Which Livewire and Alpine major versions are supported, and is there a compatibility table?
  5. Does the toggle honor prefers-color-scheme on first visit before any user choice exists?
  6. What is the exact a11y contract for the Laravel UX UI toggle (role, aria-pressed/aria-checked, keyboard, focus ring, contrast)?
  7. What does the Laravel Boost skill actually do — scaffold code, or advise? Is its output reviewable in a PR?
  8. Who maintains the package, and what is the release cadence and support window?

Integration Approach

Stack fit. Requires Laravel with Blade, Livewire (v3-era expected), Alpine, Tailwind with darkMode: 'class', and the Laravel UX UI + Icons components. Confirm each is already present or acceptable before adoption; the UX UI/Icons dependency is the most likely to be a blocker for teams with an established design system.

Migration path. Two distinct paths:

  • Greenfield / no existing theming: adopt directly, no migration.
  • Existing custom dark mode: audit and remove the incumbent implementation first — localStorage keys, media-query listeners, class writers, and any inline head scripts. Then migrate storage to whatever the package expects and reconcile any persisted user preference. Do not run both in parallel; the overlap window is where the bugs live.

Compatibility. Pin an exact version (0.1.0, not ^0.1) — pre-1.0 caret ranges admit breaking changes. Verify the supported PHP/Laravel/Livewire matrix before committing. Check interaction with wire:navigate, any full-page cache layer, and CSP. Plan for a Tailwind config change and a layout template change, both of which touch shared surface area across every page.

Sequencing.

  1. Read the docs and the Boost skill output; validate the a11y and first-paint claims in a throwaway branch.
  2. Spike in a single low-traffic app shell: directive in <head>, toggle in the nav, verify no flash and no CSP violation.
  3. Validate cross-tab sync, wire:navigate persistence, and session behavior against the event contract.
  4. Only then roll to the primary layout and remove any legacy theming.
  5. Define an upgrade owner and a re-test checklist before the first version bump.

Operational Impact

Maintenance. Low code volume, but non-zero attention: pre-1.0 means every minor release is a potential breaking change requiring review. Exact version pinning plus an owner for upgrades is mandatory. If the package goes quiet, the fallback is small — the directive is a few lines of inline script and the toggle is a Blade component — so the exit cost is low, which is the main mitigant.

Support. Documentation covers installation, usage, events, customization, and AI assistance, which is more than most 0.1.0 packages offer. The dark-mode-toggled event is the extension point; treat it as the supported customization seam and avoid depending on internals. No SLA, no LTS, likely single-maintainer — plan accordingly.

Scaling. Negligible runtime cost: one class write and an Alpine store update per toggle. Watch two things at scale: session writes per toggle (cheap, but non-zero under heavy interaction) and caching. If theme is server-rendered from session, full-page caches must vary on that state or the cache will serve the wrong theme; if it is client-rendered pre-paint, caching is unaffected. Confirm which before turning on any page cache.

Failure modes.

  • Theme flash or wrong theme on first paint (late script, CSP block, cache).
  • Desync between session, Alpine store, and DOM after wire:navigate or cross-tab toggling.
  • Double-toggle from an unremediated legacy implementation.
  • Dependency breakage on a Livewire or Alpine major, surfacing as a silently inert toggle.
  • Accessibility regression if the UX UI toggle's semantics change underneath the package.
  • CSP violations from inline script emission.

Ramp-up. Under a day for a developer comfortable with Blade, Livewire, and Alpine: the directive placement, the component tag, and the event name are the whole API. Expect a further half-day for a11y verification and CSP validation, and roughly a day of cleanup if replacing an existing dark mode implementation. The Boost skill lowers the floor for teams using AI assistance but does not substitute for reviewing the generated integration — mandate PR review of any AI-scaffolded output.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle