Vuetify toggle between light and dark theme (with vuex)

Viewed 22113

so in my Vue-project I basically have two pages/components that will be shown with the use of vue-router depending on the URL. I can switch between those pages/components via a button.

I am also using VueX for the management of some data.

Now I included a switch in one of the components to toggle between a dark and a light theme from Vuetify.

In the template for this component I do:

    <v-switch
      label="Toggle dark them"
      @change="toggleDarkTheme()"
    ></v-switch>

And in the function that gets called I do:

    toggleDarkTheme() {
          this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
          console.log(this.$vuetify.theme.dark);
    },

In app.vue I have included the <v-app dark> and in my main.js i have the following:

    Vue.use(Vuetify);
    const vuetify = new Vuetify({
      theme: {
        // dark: true,
        themes: {
          light: {
            primary: colors.purple,
            secondary: colors.grey.darken1,
            accent: colors.shades.black,
            error: colors.red.accent3,
            background: colors.indigo.lighten5, 
          },
          dark: {
            primary: colors.blue.lighten3,
            background: colors.indigo.base,
          },
        },
      },
    });
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      store,
      vuetify,
      render: (h) => h(App),
    }).$mount('#app');

So my problem now is, when I click the switch, the theme is indeed toggled from light to dark mode in this component. Light mode is the default and when I click the switch once, I get dark theme. However when I click the button to switch to the other URL, there the light theme will be used. How do I implement this feature correctly?

Thanks in advance!

3 Answers

You should have a JavaScript class called vuetify.js, that should look like this in your case.

import Vue from "vue";
import Vuetify from "vuetify/lib";

Vue.use(Vuetify);

export default new Vuetify({
  theme: {
    themes: {
      light: {
        primary: colors.purple,
        secondary: colors.grey.darken1,
        accent: colors.shades.black,
        error: colors.red.accent3,
        background: colors.indigo.lighten5
      },
      dark: {
        primary: colors.blue.lighten3,
        background: colors.indigo.base
      }
    }
  }
});

Your switch should be working, but just in case, try this button I've made in your component.

    <div>
      <v-tooltip v-if="!$vuetify.theme.dark" bottom>
        <template v-slot:activator="{ on }">
          <v-btn v-on="on" color="info" small fab @click="darkMode">
            <v-icon class="mr-1">mdi-moon-waxing-crescent</v-icon>
          </v-btn>
        </template>
        <span>Dark Mode On</span>
      </v-tooltip>

      <v-tooltip v-else bottom>
        <template v-slot:activator="{ on }">
          <v-btn v-on="on" color="info" small fab @click="darkMode">
            <v-icon color="yellow">mdi-white-balance-sunny</v-icon>
          </v-btn>
        </template>
        <span>Dark Mode Off</span>
      </v-tooltip>
    </div>

The Button calls this method in your <script>

darkMode() {
      this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
    }

The below code creates a dark mode toggle switch btn.

Note: Its use Localstore

DarkModeToggel.vue


<template>
   <v-icon class="mr-2">
      mdi-brightness-4
   </v-icon>
   <v-list-item-title class="pr-10">
      Dark Mode
   </v-list-item-title>
   <v-switch v-model="darkmode" color="primary" />
</template>

--

<script>
export default {
  data () {
    return {
      darkmode: false
    }
  },
  watch: {
    darkmode (oldval, newval) {
      this.handledarkmode()
    }
  },
  created () {
    if (process.browser) {
      if (localStorage.getItem('DarkMode')) {
        const cookieValue = localStorage.getItem('DarkMode') === 'true'
        this.darkmode = cookieValue
      } else {
        this.handledarkmode()
      }
    }
  },
  methods: {
    handledarkmode () {
      if (process.browser) {
        if (this.darkmode === true) {
          this.$vuetify.theme.dark = true
          localStorage.setItem('DarkMode', true)
        } else if (this.darkmode === false) {
          this.$vuetify.theme.dark = false
          localStorage.setItem('DarkMode', false)
        }
      }
    }
  }
}
</script>

@ckuessner answer is working but not persistent.

Button theme switcher with persistence of dark theme state in cookies based on solution of @rohit-nishad.

NPM package used for cookies reading/writing: 'cookie-universal-nuxt'.

ColorThemeSwitch.vue

<template>
  <v-tooltip bottom>
    <template #activator="{ on }">
      <v-btn v-on="on" icon @click="switchTheme">
        <v-icon>
          {{ $vuetify.theme.dark ? 'mdi-white-balance-sunny' : 'mdi-moon-waxing-crescent' }}
        </v-icon>
      </v-btn>
    </template>
    <span>Change theme</span>
  </v-tooltip>
</template>

<script>
export default {
  created() {
    const darkModeCookie = this.$cookies.get('app.darkMode');
    if (darkModeCookie) {
      this.$vuetify.theme.dark = darkModeCookie;
    }
  },
  methods: {
    switchTheme() {
      this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
      this.$cookies.set('app.darkMode', this.$vuetify.theme.dark);
    },
  },
};
</script>

It is better to put the code from 'created' hook somewhere in layouts or plugin so your app will change the theme no matter if component is presented on the current page. Example for plugin:

~/plugins/persistedThemeLoader.js

export default function ({ $vuetify, $cookies }) {
  const darkModeCookie = $cookies.get('app.darkMode');
  if (darkModeCookie) {
    $vuetify.theme.dark = darkModeCookie;
  }
}

nuxt.config.js

plugins: [
    '~/plugins/vuetify',
    { src: '~/plugins/persistedThemeLoader', mode: 'client' },
],
Related