DEV Community

Cover image for How to make a Dark-Mode in ASP.NET MVC 7
Vlank
Vlank

Posted on • Edited on

How to make a Dark-Mode in ASP.NET MVC 7

While creating my portfolio I found the need to implement a dark mode with no more than a few tools, because this project was made to learn ASP.NET, not a javascript framework. So go on...

Tools

  • C#
  • CSS
  • JavaScript

Some background

When I was researching about how to make a dark mode I found this website. I followed up the "body-class" method, all worked fine but when I refresh the page the theme doesn't persist. Then, I tried to save data to local storage with JavaScript, but it didn't work, so I decided to use cookies.

Method 1 - LocalStorage

In this way, we keep the changes of the view on the client-side.

Step 1

Add a class to the components that you want to change their theme. This class will be your default theme, so keep it in mind.

// Shared/_Layout.cshtml
<body class="dark-theme">
  @RenderBody()
<script src="~/js/site.js" asp-append-version="true"></script>
</body>
// Views/Home
<div class="home-lower dark-theme">
</div>
Enter fullscreen mode Exit fullscreen mode

Step 2

Add a script to remove the class name based on the local storage variable name.

const themeName = 'dark-theme';
const itemDivs = document.querySelectorAll('.dark-theme');
const themeSwitcher = document.getElementById('theme-switcher');
const darkTheme = localStorage.getItem(themeName);

if(darkTheme === null){
localStorage.setItem(themeName,"active");
} else if(darkTheme === "active"){
addTheme();
} else {
removeTheme();
}

themeSwitcher.addEventListener('click',function (){
let currentTheme = localStorage.getItem(themeName);
if(currentTheme === "inactive"){
localStorage.setItem(themeName,"active");
addTheme();
} else if (currentTheme === "active"){
localStorage.setItem(themeName,"inactive");
removeTheme();
}
})

function removeTheme(){
itemDivs.forEach(itemDiv => {
itemDiv.classList.remove(themeName);
});
}

function addTheme(){
itemDivs.forEach(itemDiv => {
itemDiv.classList.add(themeName);
});
}

Enter fullscreen mode Exit fullscreen mode

Step 3

Add a button with an id to be listened by the event from the script (tutorial)

<button class="btn-toggle" id="theme-switcher"></button>
Enter fullscreen mode Exit fullscreen mode

Step 4

Add your css rules to change your colors based on class name

body {
    background-color: white;
}
body.dark-theme {
    background-color: gray;
}
Enter fullscreen mode Exit fullscreen mode

Method 2 - Cookies

This way, you need to call an action in the controller to make a new request to the server, but you will need to update the DOM with Javascript (Looking back, it sounds terrible to separate the logic between client and server).

HTTP Context

Reading about the request pipeline, we can find HttpContext class, which describes request and response information. In this case, we need to read the user request available through the Request member.

public abstract class HttpContext
{
  public abstract HttpRequest Request { get; }
}
Enter fullscreen mode Exit fullscreen mode

And what do we need to know about the request? ๐Ÿช๐Ÿช๐Ÿช

Cookies

We will use cookies to store our dark theme information in something like ["dark-theme" = true]and it is available through the Cookies request member.

public abstract class HttpRequest
{
  public abstract IRequestCookieCollection Cookies { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Executing request

As I tried to avoid using javascript except to handle the DOM, we will use an Action from our Controller to check if the user is requesting dark or light theme. Let's go

How it works?

The theme changer will be executed on the Home view of my website. It will trigger another action method from the HomeController and redirect to the Index action of that controller.

Step 1

Add a class to the components that you want to change their theme. This class will be your default theme, so keep it in mind.

// Shared/_Layout.cshtml
<body class="dark-theme">
  @RenderBody()
<script src="~/js/site.js" asp-append-version="true"></script>
</body>
// Views/Home
<div class="home-lower dark-theme">
</div>
Enter fullscreen mode Exit fullscreen mode

Step 2

Add a script to remove the class name based on the cookie name. I use the readCookie method from a Quirksmode post and the script from ChatGPT because is not a technology that I handle.
โš ๏ธ It's important that your template runs javascript on the pages where you will use the method to change the theme, that's why I used the base layout from ASP.NET

// wwwroot/js/site.js
const darkTheme = 'dark-theme'; // Your class name
const itemDivs = document.querySelectorAll('.dark-theme');
// If dark theme is active, remove class names
if(readCookie(darkTheme) === 'true'){
    itemDivs.forEach(itemDiv => {
        itemDiv.classList.remove(darkTheme);
    });
}

function readCookie(name) {
    const nameEQ = name + "=";
    const ca = document.cookie.split(';');
    for(let i=0; i < ca.length; i++) {
        let c = ca[i];
        while (c.charAt(0)===' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}
Enter fullscreen mode Exit fullscreen mode

Step 3

Add a button to execute an action method called ToggleTheme in your HomeController

<div>
  <a asp-action="ToggleTheme" asp-controller="Home">
</div>
Enter fullscreen mode Exit fullscreen mode

Step 4

Add a method to set a default cookie called as your theming class
(dark-theme == false equals to "keep class name", and yeah, it is bad, do it better)

public class HomeController : Controller
{
  public IActionResult Index()
    {
        var requestCookie = HttpContext.Request.Cookies;
        var response = HttpContext.Response.Cookies;
        if (!requestCookie.ContainsKey("dark-theme"))
        {
            response.Append("dark-theme","false");
        }
        return View("Home");
    }
}
Enter fullscreen mode Exit fullscreen mode

Add a method to change your cookie value based on user request and redirect to index because when you return the view your url will be like /Home/ToggleTheme

public IActionResult ToggleTheme()
{
   var requestCookies = HttpContext.Request.Cookies;
   var responseCookies = HttpContext.Response.Cookies;
   if (requestCookies.ContainsKey("dark-theme") && requestCookies["dark-theme"]!.Contains("false"))
     {
         responseCookies.Append("dark-theme","true");
     }
     else
     {
         responseCookies.Append("dark-theme","false");
     }
     return RedirectToAction("Index");
}
Enter fullscreen mode Exit fullscreen mode

Step 5

Add your css rules to change your colors based on class name

body {
    background-color: white;
}
body.dark-theme {
    background-color: gray;
}
Enter fullscreen mode Exit fullscreen mode

That's all

If you have any corrections I look forward to your comments, I didn't find much information on StackOverflow or Youtube so I made it with what I know. I hope I haven't forgotten anything

Code: https://gitlab.com/vlank/portfolio

Greetings from ๐Ÿ‡ฆ๐Ÿ‡ท

Top comments (3)

Collapse
 
lil5 profile image
Lucian I. Last

This is bad advice, please read about prefers-color-scheme media feature.

I am interested in hearing why ** Then, I tried to save data to local storage with JavaScript, but it didn't work** didnโ€™t work

Usually one should follow the prefers-color-scheme first and have a .dark class, in the body element, that overrides the browser when changed manually.

Collapse
 
vlank profile image
Vlank • Edited

Roughly speaking, this feature would be useful if you wanted to detect the user's preferred theme? (But if I want to keep my default theme and allow the user to change it, it would not... maybe).
And about local storage, I made a mistake while testing and testing things, because it works keeping the same approach. I will rewrite these things later
Edit: I think one of the reasons I didn't use local storage was because I wanted to keep that logic server-side and handled by C#

Collapse
 
lil5 profile image
Lucian I. Last

this feature would be useful if you wanted to detect the user's preferred theme

The consensus around how to implement dark theme is to adhere to the OS preferences first, most, if thereโ€™s a slider available, will not change it for every website they go to & you might as well not add dark mode altogether.