A photo of a blood moon by Sander Dewerte on Unsplash

Making a Vuejs dark theme toggle

Updated | 2 min read

Making a dark theme with CSS variables and @media

If you haven't read my previous article on making a dark theme with CSS variables. Check it out before reading this because this is a continuation of that article.

The first called script

This script should be called as soon as possible so that the proper CSS can be applied to the document. If you are using Gridsome, you can add this script to your index.html file. This code checks for the color of the device and then set a local storage variable and a data attribute to the theme name. For example, if the device's color scheme was set to 'dark mode' the local storage variable and data attribute would be set to dark.

Setting a data attribute makes it possible to change the CSS based on the color scheme.

(function() {
	try {
		// Checks for the color scheme of the device.
		// In this case it checks for anything that is not light theme.
		var media = window.matchMedia("not all and (prefers-color-scheme: light)"),
			body = document.body;
		if (localStorage.getItem("theme") == "dark") {
			body.setAttribute("data-theme", "dark");
		} else if (localStorage.getItem("theme") == "light") {
			body.setAttribute("data-theme", "light");
		} else if (media.matches) {
			body.setAttribute("data-theme", "dark");
			localStorage.setItem("theme", "dark");
		}
		media.addListener(function() {
			if (media.matches) {
				body.setAttribute("data-theme", "dark");
				localStorage.setItem("theme", "dark");
			} else {
				body.setAttribute("data-theme", "light");
				localStorage.setItem("theme", "light");
			}
		});
	} catch (err) {}
})();

Theme Toggle Component

In the navigation, I have made a button component to toggle the theme. This is the HTML for that component.

<template>
	<button
		:title="theme == 'dark' ? 'Dark Theme' : 'Light Theme'"
		@click="toggleTheme()"
		class="theme"
	>
		<Moon :is="theme == 'dark' ? 'Moon' : 'Sun'" height="20px" />
	</button>
</template>

<script>
	import Moon from "~/assets/images/moon-regular.svg";
	import Sun from "~/assets/images/sun-regular.svg";

	export default {
		components: {
			Moon,
			Sun
		},
		data() {
			return {
				theme: localStorage.getItem("theme")
			};
		},
		methods: {
			toggleTheme() {
				if (this.theme == "dark") {
					this.theme = "light";
					document.body.setAttribute("data-theme", "light");
					localStorage.setItem("theme", "light");
				} else {
					this.theme = "dark";
					document.body.setAttribute("data-theme", "dark");
					localStorage.setItem("theme", "dark");
				}
			}
		}
	};
</script>

If you would like to see this code in action check out the navigation on Developer Bacon.