DEV Community

Cover image for Blazor WebAssembly : Dark/Light Theme Switch
Curious Drive for Curious Drive

Posted on

Blazor WebAssembly : Dark/Light Theme Switch

Some people like dark theme and some like light theme. I implemented a switch for Blazor WebAssembly apps so that user can switch between dark and light themes.

Source code : BlazingChat

For this demo, I created two CSS files for light and dark themes. app-light.css will be the default theme for the application and app-dark.css is the dark theme of the application. Please check the code below.

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazingChat</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link id="theme" href="css/app-light.css" rel="stylesheet" />
    <!-- <link id="theme" href="css/app-dark.css" rel="stylesheet" /> -->
    <link href="manifest.json" rel="manifest" />
</head>
Enter fullscreen mode Exit fullscreen mode

I've added references in the index.html file in head tag the Blazor WebAssembly app. I've made sure to set the id of these links so that we could find these links and add and remove them from our JavaScript function

That's what we're trying to do in below JavaScript function. I namesd this function as setTheme which takes themeName as a parameter. I am adding a CSS link and removing the old theme which was set for the application. Please check the code below.

export function setTheme(themeName) {

    //add a new css link
    let newLink = document.createElement("link");
    newLink.setAttribute("id", "theme");
    newLink.setAttribute("rel", "stylesheet");
    newLink.setAttribute("type", "text/css");
    newLink.setAttribute("href", `css/app-${themeName}.css`);
    //remove the theme from the head tag
    let head = document.getElementsByTagName("head")[0];
    head.querySelector("#theme").remove();
    //adding newLink in the head
    head.appendChild(newLink);
}
Enter fullscreen mode Exit fullscreen mode

We can call this JavaScript function from our Razor component and we should be able to change the theme of our application right away. I am using JavaScript Isolation to make this call. Please check the code for Settings.razor component

<div class="col-12">
    <div class="row">
        <RadzenSwitch @bind-Value="@_settingsViewModel.DarkTheme" Style="margin-bottom: 20px" Change="UpdateTheme" />
        <span>&nbsp; &nbsp;</span>
        <label class="white-text"> Dark Theme </label>    
    </div>
</div>

@code {
private async Task UpdateTheme()
{
        //setting the themeName parameter
        var themeName = _settingsViewModel.DarkTheme ? "dark" : "light";
        //calling JS function
        var module = await _jsRuntime.InvokeAsync<IJSObjectReference>("import","./js/site.js");
        await module.InvokeVoidAsync("setTheme", themeName);
        //persisting the settings in DB
        await _settingsViewModel.UpdateTheme();
}
Enter fullscreen mode Exit fullscreen mode

This approach has one issue though, if I refresh the application then it doesn't matter which theme that the user has set it is going to set the default theme for the application, which is the light theme in this case.

To fix this issue I needed to persist the current theme somewhere. I did that in the user table that I have created in SQLite. I got the current authenticated user whenever MainLayout.razor gets initialized. and called the same JavaScript function to set the theme of the application. That way, whenever I refresh the application I don't lose the current theme. Please check the code below for OnInitializedAsync event for MainLayout.razor.

protected override async Task OnInitializedAsync()
{
        //getting the current authenticated user for the app
        User currentUser = await _httpClient.GetFromJsonAsync<User>("user/getcurrentuser");
        if(currentUser != null)
        {
            //setting the themeName parameter for JS function
            var themeName = currentUser.DarkTheme == 1 ? "dark" : "light";
            //calling the JS function
            var module = await _jsRuntime.InvokeAsync<IJSObjectReference>("import","./js/site.js");
            await module.InvokeVoidAsync("setTheme", themeName);
        }
        await base.OnInitializedAsync();
}
Enter fullscreen mode Exit fullscreen mode

If you like watching video tutorial of this blog then please click on the video below.
IMAGE ALT TEXT HERE

Thanks for reading. Bye!!!

Top comments (0)