Cómo Crear un Toggle de Modo Oscuro con Tailwind 4 (Laravel Livewire)

El modo gótico… perdón, modo oscuro en Tailwind 4. ¿Cómo lo implementamos? vamos a guardar la configuración directamente en la sesión, es decir el modo, para esto, ocuparemos Laravel Livewire pero, primero, veamos que es lo que tenemos que hacer para Tailwind 4.

Toggle Modo Oscuro/Claro en Tailwind 4

Funciona de forma similar a cómo lo hacíamos con Tailwind 3, al menos en lo que respecta a las clases CSS. Aunque hay una consideración nueva en Tailwind 4, que te explicaré a continuación.

Si seleccionas desde el navegador cualquier regla que utilices el prefijo de dark: veras algo como:

dark\:bg-gray-800 {
   @media (prefers-color-scheme: dark) {
       background-color: var(--color-gray-800);
   }
}

En Tailwind 4, el sistema por defecto utiliza @media (prefers-color-scheme), que detecta el modo del sistema operativo o navegador. Esto no se puede controlar desde JavaScript, así que un toggle como el nuestro no tendría efecto si dejamos la configuración por defecto.

Debemos de sobrescribirlo con la siguiente regla en nuestro CSS en donde carguemos a Tailwind 4:

resources\css\YOURCSS.css

@import 'tailwindcss';
+ @custom-variant dark (&:where(.dark, .dark *));

Con esto, podremos cambiar fácilmente entre un modo a otro, cambiando la clase de la etiqueta HTML desde el navegador:

// document.documentElement.className = params[0].theme;
document.documentElement.classList.toggle('dark');

Paso 2: Crear el componente del toggle del tema en Laravel Livewire

Vamos a crear un componente que nos permita alternar entre modo claro y modo oscuro. También es importante destacar que (Flux) maneja su propia lógica para el tema oscuro.

$  php artisan make:livewire ThemeToggle

app\Livewire\ThemeToggle.php

<?php

namespace App\Livewire;

use Livewire\Component;

class ThemeToggle extends Component
{
    public $theme;

    public function mount()
    {
        $this->theme = session('theme', 'light');
    }

    public function toggleTheme()
    {
        $this->theme = $this->theme === 'light' ? 'dark' : 'light';
        session(['theme' => $this->theme]);
        $this->dispatch('theme-changed', ['theme' => $this->theme]);
    }

    public function render()
    {
        return view('livewire.theme-toggle');
    }
}

Si buscas por ejemplo "Flux dark mode", verás que tiene su propio switcher (Dark/System/Light), pero no es lo que vamos a usar aquí. Yo quiero usar una implementación personalizada, ya que prefiero mantener esta web lo más ligera posible y sin tantas dependencias. No quiero agregar JavaScript adicional innecesario para el usuario final.

Yo prefiero algo más controlado. Ya con Tailwind es más que suficiente, y quizás uno que otro script o CSS adicional, como en este caso Flux para ciertos estilos. Pero no quiero que este curso dependa tanto de tecnologías externas que cambian constantemente, como ocurre con Laravel.

Si no hay valor definido, colocamos un valor por defecto (en este caso, light, aunque puedes colocar dark si prefieres):

$this->theme = session('theme', 'light');

Si el modo actual es light, cambia a dark, y viceversa:

$this->theme = $this->theme === 'light' ? 'dark' : 'light';

Establecer el nuevo valor en la sesión y despachar un evento al cliente para que aplique los cambios.
También podríamos recargar la página, aunque hay muchas formas de hacerlo:

$this->dispatch('theme-changed', ['theme' => $this->theme]);
***
Livewire.on('theme-changed', (params) => {
    // document.documentElement.className = params[0].theme;
    document.documentElement.classList.toggle('dark');
})

La vista del botón es simple. Colocamos un botón con la etiqueta Change Mode:

<div>
    <flux:button wire:click="toggleTheme">
        {{ __('Change mode') }} {{ $theme === 'light' ? __('Dark'): __('Light') }}
    </flux:button>
</div>

En el botón mostramos "Dark" o "Light" según el modo que esté activo, pero recuerda que debe ser la opción hacia la cual vas a cambiar, no la actual. Es decir, si el modo actual es light, el botón debería decir Dark.

Acepto recibir anuncios de interes sobre este Blog.

Te muestro unos sencillos pasos para emplear el modo oscuro en Tailwind 4 y también en Laravel Livewire.

- Andrés Cruz

In english