Search code examples
htmlsass

How do I use a HTML data-attribute in SCSS?


I was looking for a simple way to implement dark/light mode on my site and have settled on this method as of right now:

Setting a data attribute on the body that contains the current theme

<body name="body" theme="dark">

A JavaScript function to swap between the themes:

let themeToggle = document.getElementById("theme-toggle")
let body = document.getElementsByName("body").item(0)
let currentTheme = body.getAttribute("theme")

function toggleTheme() {
    currentTheme = (currentTheme == "dark") ? "light" : "dark"
    body.setAttribute("theme", currentTheme)
}

With the current approach I am currently splitting my CSS into multiple CSS/SCSS files, a layout one (syle.scss), a dark.scss, a light.scss and a _colors.scss.

However, with this I end up with two very similar SCSS files like this:

dark.scss:

@use 'colors' as c;

body[theme="dark"] {
    background-color: c.$dark-background;

    #theme-toggle {
        border-color: c.$light-background;
    }

    div {
        background-color: c.$dark-accent;
    }
}

light.scss:

@use 'colors' as c;

body[theme="light"] {
    background-color: c.$light-background;

    #theme-toggle {
        border-color: c.$dark-background;
    }

    div {
        background-color: c.$light-accent;
    }
}

Now I am wondering if there was a possibility to do something like this:

body {
    $activeTheme: attr(theme);
    @if $activeTheme == "dark" {
        $inactiveTheme: "light";
    } @else {
        $inactiveTheme: "dark";
    }

    background-color: c.{$activeTheme}-background;

    #theme-toggle {
        border-color: c.{$inactiveTheme}-background;
    }

    div {
        background-color: c.{$activeTheme}-accent;
    }
}

I have tried to use interpolation, but I can't quite get it to work.


Solution

  • It's not possible to use Sass in this way. Sass is compiled to CSS before it is sent client-side, so by the time it's in a user's browser alongside the HTML and JS, Sass variables don't exist anymore and any interpolation has already happened.

    Consider swapping stylesheets based on the theme mode, or using regular CSS variables.