I just wanted to quickly document the steps I took to make a theme toggle for a client.
Note: This is just one of many methods to do this, and I just found my task a lot easier once I implimented a few intersting tools.
β Watch this Video and Understand the Implications of Dark Mode Color Selections.
Be sure to plan for dark mode first. Also, watch anything and everything that Juxtopposed puts out. Totally worth it!
Plan for Dark Mode first!
β Get your Realtime Colors On
Head over to Realtime Colors, from Juxtopposed and hit dark mode. Plan and swap back and forth till you are happy.
If you need help, use this video.
β Grab your TailwindCSS vars from Realtime Colors
- Place variables in a
global.css
file.
// Random Color Selection just for example
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--text: #101823;
--background: #f7f7f7;
--primary: #cd71f4;
--secondary: #fb9518;
--accent: #f27d7d;
}
.dark {
--text: #dce4ef;
--background: #080808;
--primary: #670b8e;
--secondary: #e78104;
--accent: #800d0d;
}
}
- Modify
tailwind.config.cjs
to use the variables. Seeting thedarkMode: class
export, it makes it very easy to simply swap themes based on CSS toggling with minimal JS.
// Ensure this content is present
module.exports = {
// ...
darkMode: 'class',
theme: {
fontSize: {
sm: '0.750rem',
base: '1rem',
xl: '1.333rem',
'2xl': '1.777rem',
'3xl': '2.369rem',
'4xl': '3.158rem',
'5xl': '4.210rem'
},
colors: {
text: 'var(--text)',
background: 'var(--background)',
primary: 'var(--primary)',
secondary: 'var(--secondary)',
accent: 'var(--accent)'
},
// ...
};
- Create Toggle components
<div class="flex w-[70px] items-center justify-end">
<label class="relative inline-block h-[34px] w-[65px]" for="checkbox">
<input class="hidden" type="checkbox" id="checkbox" />
<div
class="slider bg-accent checked:bg-accent absolute bottom-0 left-0 right-0 top-0 cursor-pointer rounded-full transition-transform"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="var(--background)"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lightsun bottom-[9px] right-[9px] translate-x-0 opacity-100"
>
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="var(--background)"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="darkmoon bottom-[9px] left-[9px] translate-x-[4px] opacity-0"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</div>
</label>
</div>
<style>
/* I'm still working on shifting everything to tailwind, but at least it's here! */
.slider:before {
background-color: var(--background);
bottom: 4px;
content: "";
height: 26px;
left: 4px;
position: absolute;
transition: 0.4s;
width: 26px;
border-radius: 50%;
}
input:checked + .slider:before {
transform: translateX(26px);
}
.slider svg {
color: var(--text);
position: absolute;
transition:
opacity 0.2s ease 0s,
transform 0.35s ease 0s;
pointer-events: none;
}
input:checked + .slider .darkmoon {
opacity: 1;
transform: translateX(0);
}
input:checked + .slider .lightsun {
opacity: 0;
transform: translateX(-4px);
}
</style>
Place the code below in a <script>
tag in the .astro
component.
const themeToggle = document.querySelector('input[type="checkbox"]');
const currentTheme = localStorage.getItem("theme");
if (currentTheme) {
document.documentElement.classList.add(currentTheme);
if (currentTheme === "dark") {
themeToggle.checked = true;
}
}
function switchTheme(e) {
if (e.target.checked) {
document.documentElement.classList.add("dark");
document.documentElement.classList.remove("light");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.add("light");
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
}
}
themeToggle.addEventListener("change", switchTheme);
Import the component where ya want and enjoy!
π Explaination
By having the variables set in the global.css
file, itβs insanely easy to have all the values for the variables change simply by adding the class dark
to the html
DOM element.