How-to: Switch dark mode using TailwindCSS + Vue3 + Vite
P粉933003350
P粉933003350 2023-11-01 12:05:00
0
1
722

I am a beginner in Vite/Vue3 and currently I am facing a problem where I need the combined knowledge of the community.

I created a Vite/Vue3 application and installed TailwindCSS:

npm create vite@latest my-vite-vue-app -- --template vue
cd my-vite-vue-app
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

I then followed the instructions on the Tailwind homepage:

Add the paths of all template files in the tailwind.config.js file.

Import the newly created ./src/index.css file into the ./src/main.js file.

Create a ./src/index.css file and add the @tailwind directive Tailwind layer to each file.

Now I have a Vite/Vue3/TailwindCSS app running and want to add the ability to toggle dark mode.

Tailwind documentation says that archiving can be done by adding darkMode: 'class' to tailwind.config.js and then switching the class dark to <html> tag.

I accomplished this using the following code:

  1. Internalindex.html



<html lang="en" id="html-root">
  (...)
  <body class="antialiased text-slate-500 dark:text-slate-400 bg-white dark:bg-slate-900">
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
  1. About.vue internal



<template>
  <div>
    <h1>This is an about page</h1>
    <button @click="toggleDarkMode">Toggle</botton>
  </div>
</template>

<script>
  export default {
    methods: {
      toggleDarkMode() {
        const element = document.getElementById('html-root')
        if (element.classList.contains('dark')) {
          element.classList.remove('dark')
        } else {
          element.classList.add('dark')
        }
      },
    },
  };
</script>

Yes, I know this is not Vue3 style code. And, yes, I know you can use element.classList.toggle() instead of .remove() and .add() . But maybe other beginners like me will see this in the future and appreciate some simple code to start with. So please have mercy...

Now I finally have to ask the community a question:

I know that manipulating the DOM like this is not the Vue way of doing things. Of course, I want to achieve my goals in the right way. But what should I do?

Trust me, I searched on google for hours and didn't find a solution that works without installing this and this and this extra npm module.

But I wanted a minimalist approach. Depend on as little as possible so as not to overwhelm me and others who want to start learning.

With this as background - do you have a solution that would work for me and other newbies? :-)

P粉933003350
P粉933003350

reply all(1)
P粉340264283

The target element of your event is located outside your application. This means there is no way to interact with it other than querying it through the methods available in the DOM.

In other words, You did the right thing. If the element is inside your application, then you can just link the class to your attribute and let Vue handle the details of DOM manipulation:

:class="{ dark: darkMode }"

but it is not the truth.


As a side note, it is very important that your toggle method does not depend on whether the <body> element has that class in order to decide if it should be applied/removed. You should persist the values ​​saved in the application state, which should be your only source of truth.
This is the Vue principle you don't want to break: let the data drive the DOM state, not the other way around.

The value can be obtained from the current state of <body> (when installed), but from that point on, changes to the application state will determine whether the class is present on the element.

vue2 Example:

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    darkMode: document.body.classList.contains('dark')
  }),
  methods: {
    applyDarkMode() {
      document.body.classList[
        this.darkMode ? 'add' : 'remove'
      ]('dark')
    }
  },
  watch: {
    darkMode: 'applyDarkMode'
  }
})
body.dark {
  background-color: #191919;
  color: white;
}
sssccc

View 3 example:

const {
  createApp,
  ref,
  watchEffect
} = Vue;

createApp({
  setup() {
    const darkMode = ref(document.body.classList.contains('dark'));
    const applyDarkMode = () => document.body.classList[
      darkMode.value ? 'add' : 'remove'
    ]('dark');
    watchEffect(applyDarkMode);
    return { darkMode };
  }
}).mount('#app')
body.dark {
  background-color: #191919;
  color: white;
}
sssccc

Obviously, if you are using the state of darkMode in multiple components, you may want to keep the state of darkMode somewhere outside of data in storage, not locally (and provide it in your component via compulated).

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template