DEV Community

Cover image for 🌙 How to implement darkmode with a Vue.js component

🌙 How to implement darkmode with a Vue.js component

tq-bit on June 27, 2021

Implementing darkmode in your webapp will be sugar for your nightowl readers. It implements a high-contrast color scheme that's soothing for the ey...
Collapse
 
asparoth profile image
NoobDev

Hi there!
When I move pages, the button always has the toggle animation (even though the correct theme is active) when I enable dark mode.
So if I go from one page to the other, the toggle will initially move again while keeping the theme intact.

Any ideas? I went over your code and it looks the exact same for the script part.

Collapse
 
tqbit profile image
tq-bit

Are you using the component within a router-view? It's possible the animation gets triggered whenever the component re-renders.

mounted() {
  const initUserTheme = this.getTheme() || this.getMediaPreference();
  this.setTheme(initUserTheme);
}
Enter fullscreen mode Exit fullscreen mode

You could try and place the component outside of <vue-router />.

Alternatively, you could try to abstract the CSS positioning into a separate class & dynamically apply it to the template:

<label for="checkbox" class="switch-label">
  <span>🌙</span>
  <span>☀️</span>
  <div
    class="switch-toggle"
    :class="{ 
        'switch-toggle-checked': userTheme === 'dark-theme', 
        'switch-toggle-unchecked': userTheme === 'light-theme'
     }"
  ></div>
</label>
Enter fullscreen mode Exit fullscreen mode

If you can, please share your source code and I'll have a closer look :-)

Collapse
 
asparoth profile image
NoobDev • Edited

So what I found out is that the transition css element should only be triggered on a click and now it triggers on every load.
The second solution didn't do it for me either.
My component is not being triggered within the vue router, but i found a different solution which is a little bit hacky:

.switch-toggle-checked {
transform: translateX(calc(var(--element-size) * 0.6)) !important;
transition: none;
}

This only shows the transition animation if you're in light mode.

Thank you a lot for this tutorial! It helped me a lot

Collapse
 
violacase profile image
violacase • Edited

Odd that I am the first one to react here. For this article is GREAT!
And above all: All steps work till the very end. Congrats.

Collapse
 
violacase profile image
violacase • Edited

That being said... getMediaPreference() is not a good idea for lots of reasons.
Simply replace it with a get from localStorage with f.i.:

getTheme() {
this.setTheme(localStorage.getItem("user-theme"))
},

Collapse
 
tqbit profile image
tq-bit

Thank you for your reply. & you got a valid point. I'll add your suggestion here & in the code sandbox. Will keep the getMediaPreference() as a default tho

Thread Thread
 
violacase profile image
violacase

Why keep it as a default? It really is BAD. My solution is SIMPLE, easy to implement and last but not least: secure and without any issues on all kind of browsers. My 2 pennies.

Thread Thread
 
tqbit profile image
tq-bit

With default, I meant as much as 'if there's no previous user preference in localStorage, use the result from getUserPreference. Please pick me up though on what's bad about reading out "(prefers-color-scheme: dark)" (besides missing support for IE11). I've seen it in other implementations and never had any issues using it.

Thread Thread
 
violacase profile image
violacase • Edited

Oké. I was in error. Nothing wrong with getUserPreference. Thanks and good luck with all your work.:-)

BTW: for just toggling between two color themes you can also do it with plain CSS. See developer.mozilla.org/en-US/docs/W...