Photo: Material.io
I use Vue.js and Vuetify for almost all of my websites and I’m a huge supporter of dark mode. One of the many reasons I chose Vuetify is because it has dark mode support out-of-the-box. So, without further ado, let me guide you through easily changing the dark mode state.
Setting the Default Dark Mode State
In order to set the default dark mode state, we have to open the plugin file for Vuetify, which is available at src/plugins/vuetify.js
. By default, the file should look like the following.
import Vue from "vue";
import Vuetify from "vuetify/lib";
Vue.use(Vuetify);
export default new Vuetify({});
To set the default state, we have to create a new object in the constructor called theme
, and inside of that, set a variable called dark
to true
.
export default new Vuetify({
theme: {
dark: true
}
});
But if we want to change it from the user-facing interface, we have to use the variable provided by Vuetify.
Setting the Dark Mode State From the Interface
A copy of the final code is available at the bottom.
Before even adding the theme state-changing code, you have to decide where to put the code. You only have to put it in one location, preferably a location that is persistent, such as your App.vue
or a component that is present on all pages, such as a navigation bar. With that decided, we can actually get to work.
In your file (I’m using a component that I’ve called NavigationBar
), go to the script
tag. There should be an export
statement present. If not, go ahead and create it. The contents of the script
tag should look similar to this:
export default {
name: "NavigationBar"
}
First, we need to add the method that will be called when the user clicks on a button. Underneath the name
parameter, add a new object called methods
.
export default {
name: "NavigationBar",
methods: {}
}
I’m going to call my method toggleDarkMode
, but feel free to call it whatever you’d like. This method is going to set the dark mode variable (this.$vuetify.theme.dark
) to the inverse of what it is currently set to (if the theme is currently light, then this variable will be false
), then set a local storage variable called darkTheme
to the value of that variable.
methods: {
toggleDarkMode: function() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
localStorage.setItem("darkTheme", this.$vuetify.theme.dark.toString());
}
}
With the function implemented, we now have to make it so that site will automatically pick up the theme state from the browser with the prefers-color-scheme
CSS media query and/or the local storage state. The prefers-color-scheme
state is set by your system.
To accomplish our task, we will use a Vue lifecycle hook called mounted
which is called, as you may have guessed, when the component is mounted. We’ll add mounted() {}
underneath the methods
object.
export default {
name: "NavigationBar",
methods: { ... },
mounted() {}
}
We will first check what the value of our local storage variable is. If it exists, this.$vuetify.theme.dark
is set to the value of the variable. If it doesn’t, we’ll check whether the user has dark mode enabled on their system, and set it to that.
mounted() {
const theme = localStorage.getItem("darkTheme");
// Check if the user has set the theme state before
if (theme) {
if (theme === "true") {
this.$vuetify.theme.dark = true;
} else {
this.$vuetify.theme.dark = false;
}
} else if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
this.$vuetify.theme.dark = true;
localStorage.setItem(
"darkTheme",
this.$vuetify.theme.dark.toString()
);
}
}
All that’s left is to add a button to toggle the state. In the template
tag, add the following:
<v-btn icon @click="toggleDarkMode">
<v-icon>mdi-theme-light-dark</v-icon>
</v-btn>
The code above is simple. It creates a Vuetify icon button, tells it to use the theme-light-dark
icon from Material Design Icons and to add an event handler, which on click, calls the toggleDarkMode
method.
That’s it. You’re finished! As I mentioned earlier, the final code is available on this GitHub Gist.
Thanks for reading!
Top comments (0)