5

I'm currently making a "Change Theme" button so that I can switch the whole page between "Dark Mode" and "Light Mode". But I can't find a way to change the background colour of the whole page.

Basically, I need to change the style of <body> (It's the only way I can come up with). My thought is, when you click "Change Theme" button, the <body> element will be added a class "dark-theme". And then I just simply define "dark-theme" in CSS like this:

body {
    background-color: #FFFFFF;
    color: #000000;
}

    body.dark-theme {
        background-color: #5A5A5A;
        color: #F2F2F2;
    }

I think this quite makes sense but as you can see below, I cannot access <body> element so there is no way for me to add class or change CSS of it.

MainLayout.razor

@inherits LayoutComponentBase
@using System.Web;
<div class="sidebar">
    <NavMenu />
</div>

<div>
    <LoginDisplay />
    <button id="change-theme-btn" @onclick="ThemeChanged">Change Theme</button>
    @Body
</div>

@code {
    bool isDark = false;
    private void ThemeChanged()
    {
        isDark = !isDark;
    }
}

So how do I change class or CSS of <body> element? Or if you have any alternative solution, please tell me. Thank you!

Stephen Z.
  • 168
  • 1
  • 2
  • 7
  • Do you have to use a `` tag for this purpose? Can't you use any element that you can control inside `` tag? I think you can spread a `
    ` element into full window size using CSS styling.
    – jsakamoto May 07 '20 at 14:31

3 Answers3

7

Blazor should have a simple way to do this but, at the moment, it doesn't. Hopefully it will one day soon.

I made a component to solve this problem. It allows you set the CSS class of the page's body element from a page or component. You can also set the lang attribute and the dir attribute to set the language and text-direction of the page. These were all the attributes I thought you might want to change but you could add more if you needed.

You can download the code here: https://github.com/BenjaminCharlton/BlazorBody

Or here's a summary of how to do it:

  1. Make a little JavaScript file to manipulate the body element in scripts/BodyElement.js

    var getBodyElement = function() {
        return document.getElementsByTagName("body")[0];
    }
    
    var addCssClassToBody = function (cssClass) {
        var body = getBodyElement();
    
        if (!body.classList.contains(cssClass)) {
            body.classList.add(cssClass);
        }
    }
    
    
    var setLanguageOfBody = function (language) {
        var body = getBodyElement();
        body.lang = language;
    }
    
    var setTextDirectionOfBody = function (direction) {
        var body = getBodyElement();
        body.dir = direction;
    }
  1. Place a link to your JavaScript in the section of index.html

<script src="/script/bodyelement.js"></script>
  1. Make a little CSS class to test the result.

    body {
        background: white;
        color: black;
    }
    
    body.danger {
        background: red;
        color: white;
    }
  1. Make a BodyElement razor component that you can place on any page with properties you can set from the page.

@inject IJSRuntime JSRuntime
@code {
    protected async override Task OnParametersSetAsync()
    {
        if (CssClass is { })
            await JSRuntime.InvokeVoidAsync("addCssClassToBody", CssClass);

        if (Language is { })
            await JSRuntime.InvokeVoidAsync("setLanguageOfBody", Language);

        if (TextDirection is { })
            await JSRuntime.InvokeVoidAsync("setTextDirectionOfBody", TextDirection);
    }

    [Parameter]
    public string? CssClass { get; set; } = null;

    [Parameter]
    public string? Language { get; set; } = null;

    [Parameter]
    public string? TextDirection { get; set; } = null;
}
  1. Place the BodyElement razor component on any page where you wish to manipulate the tag and set the properties

    @page "/danger"
        <BodyElement CssClass="danger" />
benjamin
  • 1,364
  • 1
  • 14
  • 26
4

Just inject IJSRuntime and use that to call a JavaScript function to make this change.

In your component:

[Inject]
IJSRuntime JSRuntime { get; set; }

Then:

private async Task ThemeChanged()
{
    isDark = !isDark;
    await JSRuntime.InvokeVoidAsync("MyInterop.ChangeTheme", isDark);
}

In your JS:

window.MyInterop = (function () {
    const _changeTheme = function (isDark) {
        if (isDark)
            document.body.classList.add('dark-theme');
        else
            document.body.classList.remove('dark-theme');
    };

    return {
        ChangeTheme: _changeTheme
    };
})();

If you haven't already, reference your JS file in _Host.cshtml, after the line to add the Blazor runtime.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
0

Or if you want pure C# code without blazor:

public string BackgroundImage { get; set; }

<style>
    body 
    {
        background-image: url(@BackgroundImage);
        width: 100%;
        height: 100%;
        background-size: 100%;
        background-repeat: no-repeat;
        background-color: darkgray;
        overflow: hidden;
    }
</style>

Or, I use Nuget package BlazorStyled:

https://github.com/chanan/BlazorStyled

And here is a sample:

<Styled @bind-Classname="CanvasStyle">
    position: fixed;
    top: 18vh;
    left: 5%;
    width: 60%;
    height: 64vh;    
</Styled>

<div class=@CanvasStyle></div>

And here is a video I made for BlazorStyled if you care to watch:

https://youtu.be/frtetHgfdIo