Alternar temas con Javascript Interop en Blazor
Para personas como yo que sufren flashbacks cada vez que abro una página web, se me ocurrió una solución súper simple sobre cómo alternar entre el modo claro y oscuro usando Javascript y llamarlo desde Blazor usando Javascript Interop.
Estableciendo el atributo padre
Primero que nada tenemos que identificar el elemento padre con un identificador, esto se debe a que cambiamos los colores dependiendo del valor de ese identificador.
Para hacer eso en Javascript, tendríamos que ejecutar este comando
document.documentElement.setAttribute('data-theme', 'YOUR_IDFENTIFIER');
En nuestro caso queremos tener dos identificadores para cada tipo de estilo, que son light y dark.
Creando un archivo Javascript para manejar la lógica
Ahora tenemos la función para actualizar el identificador, ahora creemos un archivo Javscript con una función que ejecute esa lógica. Nuestro archivo se llamará app.js

En ese archivo tendremos una función que llamará al código que mencionamos anteriormente.
var toggleTheme = function (identifier) {
document.documentElement.setAttribute('data-theme', identifier);
}
Agregar un archivo Javascript a Blazor
Agregue el script a la aplicación Blazor agregándolo donde se encuentran los scripts.
<script src="~/js/app.js"></script>
Creando el servicio
Ahora que tenemos el código Javascript, necesitamos crear un servicio que se llamará ThemeToggleService.

Este servicio manejará la lógica para alternar entre el tema light y dark.
Inyectando JSInterop
Para llamar a cualquier Javascipt, tenemos que llamar a JSInterop, por lo que debemos crear una propiedad que inyectará.
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace BlazorDarkmodeToggle.Data
{
private readonly IJSRuntime jSRuntime;
public ThemeToggleService(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
}
Función para configurar el identificador
Ahora que tenemos el servicio creado, creemos la función para configurar el identificador, esta función simplemente actualizará el data-theme en la página.
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace BlazorDarkmodeToggle.Data
{
public class ThemeToggleService
{
private readonly IJSRuntime jSRuntime;
public ThemeToggleService(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
public bool IsLightTheme { get; set; } = true;
public string GetIdentifier => IsLightTheme ? "light" : "dark";
public async Task ToggleTheme() {
IsLightTheme = !IsLightTheme;
await jSRuntime.InvokeVoidAsync("toggleTheme", GetIdentifier);
}
}
}
Agregar servicio al inicio
Para que el servicio esté disponible para todos los componentes y páginas, debemos agregarlo al archivo Program.cs.
builder.Services.AddSingleton<ThemeToggleService>();
Entonces el archivo terminará así.
using BlazorDarkmodeToggle.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddSingleton<ThemeToggleService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Tenga en cuenta que esto puede cambiar dependiendo de si usa Blazor Server o Blazor WebAssembly.
Hornear el CSS
Ahora que tenemos parte del código listo, tenemos que empezar a trabajar en el CSS. Lo que tenemos que hacer es establecer todas las propiedades CSS que manejan los colores, el fondo, etc. de CSS en una variable.
:root {
--background-color:#ffffff;
--text-color:#000000;
}
Una vez que hayamos hecho esto, usando el identificador, podemos cambiar fácilmente entre los identificadores, y usará cualquiera de otros valores.
[data-theme="dark"] {
--background-color: #000000;
--text-color: #ffffff;
}
Para que la animación se desvanezca, simplemente agregaremos una propiedad transition a todo, para que se vea bien.
* {
transition: all 250ms;
}
Ahora asignaremos estas variables a algunas clases CSS, para que podamos verlas en la página de Blazor.
.app-background {
background-color: var(--background-color);
width: 200px;
height: 200px;
}
.app-text {
color: var(--text-color);
}
Recuerde agregar el archivo a la aplicación Blazor agregándolo en el head.
<link href="css/app.css" rel="stylesheet" />
Llamando desde Blazor
Entonces, ¿cómo vamos a probar esto? Para hacerlo simple, simplemente agregaremos un div con la clase app-background, y dentro tendrá un p con la clase app-text.Entonces, creemos una página llamada Theme.razor en la carpeta Pages y agreguemos algo de código para eso.
@page "/theme"
@using BlazorDarkmodeToggle.Data
@inject ThemeToggleService ThemeToggleService
<button class="btn btn-primary" @onclick=Toggle>Toggle theme</button>
<br />
<div class="app-background">
<p class="app-text">Hello world!</p>
</div>
@code{
public async Task Toggle()
{
await this.ThemeToggleService.ToggleTheme();
}
}
Podríamos probar esto yendo a /theme, pero agreguémoslo también a la barra de navegación.
<div class="nav-item px-3">
<NavLink class="nav-link" href="theme">
<span class="oi oi-list-rich" aria-hidden="true"></span> Theme togle
</NavLink>
</div>
Pruebas

Como puede ver, tan pronto como alternamos los cambios de color de tema, fondo y fuente, ahora puede ver lo poderoso que es, si realmente desarrolla la página completa usando estas variables en CSS, podría tener diferentes temas y simplemente alternarlos.
¡¡Qué genial!!
Código
¡Este proyecto completo está en Github y puedes encontrarlo aquí!
Si tienes algún problema o pregunta, no dudes en contactarme en cualquier red social en @emimontesdeoca (en Twitter en realidad es @emimontesdeocaa con dos aa al final). También puedes encontrar la mayoría de mis redes sociales en el encabezado del blog.
Espero que os haya gustado el post!