Creating a Theme Toggle using Sass
- sass
- javascript
- design
Colors aren’t just decoration — they shape how a website feels and how usable it is. Light and dark themes can completely change that experience. Some people like the brightness, others prefer the comfort of a darker interface, and many want the choice. With Sass, we can make switching between them effortless, and in this guide, we’ll build a simple theme toggle that works instantly.
Why Sass?
I’ve used plain CSS variables, Tailwind, and even JS-based styling solutions for theming. But Sass has always had a special place in my heart. It’s stable, expressive, and makes writing modular, reusable styles a breeze.
For this project, Sass gave me exactly what I needed:
- A way to organize my colors into logical palettes.
- Loops and maps to generate CSS variables automatically.
- The flexibility to switch entire themes with minimal code duplication.
Setting the Stage: My Color Palettes
Before I wrote a single line of JavaScript, I thought about my colors. I didn’t want to sprinkle hex codes across my styles like confetti. Instead, I created two Sass maps: one for light mode, and one for dark mode.
$light-theme: (
'primary': (
'600': #d900b5,
'400': #ff85dc
),
'neutral': (
'100': #f7f7f7,
'200': #e6e9ee,
'300': #dde0e4,
'400': #818890,
'500': #535661,
'600': #4b4c53,
'700': #3a3d4a,
'800': #2e3039,
'900': #1f2028
)
);
$dark-theme: (
'primary': (
'600': #d900b5,
'400': #ff85dc
),
'neutral': (
'900': #f7f7f7,
'800': #e6e9ee,
'700': #dde0e4,
'600': #818890,
'500': #535661,
'400': #4b4c53,
'300': #3a3d4a,
'200': #2e3039,
'100': #1f2028
)
);
I kept things simple: two shades of pink for my “primary” color (buttons, highlights, links) and a range of grays for “neutral” colors (backgrounds, text). By defining them this way, I could swap the whole theme without touching every single CSS rule.
Generating CSS Variables Automatically
This is where Sass really shines. I didn’t want to write --clr-neutral-100
by hand nine times. Instead, I let Sass loop through my theme map and generate them for me.
:root {
$active-theme: $light-theme;
@each $color, $shades in $active-theme {
@each $shade, $value in $shades {
--clr-#{$color}-#{$shade}: #{$value};
}
}
}
At this point, all my colors lived as CSS variables. My light theme was the default, but that was about to change.
The Magic of Theme Switching
Switching themes was just a matter of swapping variables at the html
level. Sass made this ridiculously clean:
html[data-theme='dark'] {
@each $color, $shades in $dark-theme {
@each $shade, $value in $shades {
--clr-#{$color}-#{$shade}: #{$value};
}
}
}
The beauty of this approach? I didn’t have to rewrite my styles at all. Whether I was styling a card background or text, I just used the variables:
background-color: var(--clr-neutral-100);
Light theme or dark theme—it didn’t matter. The variables handled the heavy lifting.
Adding the Toggle (A Bit of JavaScript)
Of course, all of this was useless without a way to actually toggle the theme. Enter JavaScript:
const themeToggle = document.querySelector('.theme-toggle');
themeToggle.addEventListener('click', toggleTheme);
function toggleTheme() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme');
setTheme(currentTheme === 'dark' ? 'light' : 'dark');
}
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
}
No fancy state management. No third-party libraries. Just a click event that flips between data-theme="light"
and data-theme="dark"
.
Reflections
I’ve built complex theming systems before—some over-engineered to the point of absurdity. This time, I wanted something clean, understandable, and maintainable. Sass gave me the tools to do exactly that.
Will this theme toggle change the world? Probably not. But it does make my projects more accessible, more pleasant to use, and honestly, more fun to build. And that’s reason enough.
If you’re thinking about adding a theme toggle to your own site, I encourage you to start simple. Organize your colors, use variables, and let your tools do the heavy lifting.
Because sometimes, the best features are the ones that quietly make everything better.