Switching off the Lights Part Three - Adding Dark Mode to VuePress

Category: VuePress

Dark mode is one of the newest and hottest trends in web development. Since release of macOS 10.14 in September 2018, more and more apps are starting to offer the option for users to choose a dark system-wide interface over the standard light color scheme. Recent versions of Windows 10 and Android also started to offer dark mode layout. It is perceived that a dark background is much more easier on the eyes and attracts more readers, especially during night time. Recent study also showed that a dark background color scheme uses 6 times less battery power on smartphones. While more and more applications are adopting this feature, users also started to like it, especially at night time, when there is less light and the eyes may be exhausted by staring at the pc’s screen the whole day. I personally love it when websites have a dark mode option (also refered to as night mode) and i would like to see more and more websites implementing this feature. That is why, I have written two articles on that topic: Switching off the Lights - Adding Dark Mode to WordPress and Switching off the Lights Part Two - Adding Dark Mode to Hugo. This time, I will be swimming even deeper, by showing you how to empower visitors to switch between day and night mode in VuePress. By the end of this tutorial, you will be able to dispay a beautiful dark mode toggle with sun and moon icons like in this short video:

Wait a minute.. VuePress?!

Yes, you read it right, I am refering to VuePress, not WordPress. VuePress is a static site generator developed by vue.js author Evan You in 2018. VuePress quickly raised in popularity as one of the most promising static site generators out there. As the term suggests, static generators let you create a static site. Unlike classic CMS systems like WordPress, the pages are created at build time, using templates and markdown syntax. This makes static site generators stable, fast, cheap to maintain and secure. And there is more. As it is stated in the official documentation:

“VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded.”

This means VuePress is not just offering the stability and security that most static site generators have but also leverages a first-class user experience by acting as a SEO-optimized single page application. Last but not least, it is written in Vue.js, one of the hottest js frameworks out there. Now, enough talking, let’s get back to work!

Toggle Dark Mode in VuePress

In case you need a refreshment how to set up VuePress, you can check the following tutorial: Setting Up VuePress With Netlify Cms. We are going to make a vue.js single component called ToggleDarkMode.vue. To make it beautiful, we will take inspiration and use part of the code that is generously provided in this Codepen by Nathan Gath. We will also be using the default VuePress theme. Create “components” folder inside docs/.vuepress folder and save the new component file there. Now, go to the Readme.md file in the docs folder (our root folder) and call the component there. Your Readme.md file should look something like this:

docs/Readme.md

---
home: true
heroText: Teach me Vuepress!
heroImage: https://vuepress.vuejs.org/hero.png
actionText: Read more →
sidebar: auto
actionLink: /
features:
- title: Simplicity First
details: Minimal setup with markdown-centered project structure helps you focus on writing.
- title: Vue-Powered
details: Enjoy the dev experience of Vue + webpack, use Vue components in markdown, and develop custom themes with Vue.
- title: Performant
details: VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded
footer: MIT Licensed | Copyright © 2018-present Evan You
---

<ToggleDarkMode/>

Great, we have added the component, but it is empty, that is why we still do not see anything. Now, go back to the empty component we have just created and paste the following code:

docs/.vuepress/components/ToggleDarkMode.vue

<template>
<div class="dark-mode-widget">
    <input type="checkbox" id="theme-toggle" @click="toggleDarkTheme"></input>
    <label for="theme-toggle"><span></span></label>
</div>
</template>

<script>
export default {
mounted() {
    this.checkUserPreference();
},
methods: {
    toggleDarkTheme() {
    const body = document.body;
    body.classList.toggle("dark-mode");
    //If dark mode is selected
    if (body.classList.contains("dark-mode")) {
        //Save user preference in storage
        localStorage.setItem("dark-theme", "true");
    //If light mode is selected
    } else {
        body.classList.remove("dark-mode");
        setTimeout(function() {
        localStorage.removeItem("dark-theme");
        }, 100);
    }
    },
    checkUserPreference(){
        //Check Storage on Page load. Keep user preference through sessions
        if (localStorage.getItem("dark-theme")) {
            document.body.classList.add("dark-mode");
            document.getElementById('theme-toggle').checked = true;
        }
    }
}
};
</script>

<style>
.dark-mode-widget {
    display: table;
    margin: 1em auto;
}
body.dark-mode {
    background: #333;
}
body.dark-mode h1, body.dark-mode h2, body.dark-mode h3, body.dark-mode p {
    color: #f1f1f1
}
#theme-toggle {
    display: none;
}
#theme-toggle + label {
    font-size: 2rem;
    display: flex;
    width: 4em;
    border-radius: 2em;
    background-size: auto 8em;
    background-position: bottom;
    background-image: linear-gradient(180deg, #021037 0%, #20206A 19%, #4184B1 66%, #62E7F7 100%);
    transition: .2s;
    border: 0.125em solid #eef3f6;
    overflow: hidden;
}
#theme-toggle + label span {
    background: #fffad8;
    border-radius: 50%;
    height: 2em;
    width: 2em;
    transform: translateX(-.125em) scale(.65);
    transition: .2s;
    cursor: pointer;
    box-shadow: 0 0 .25em .0625em #fbee8d, 0 0 2em 0 #FFEB3B, inset -.25em -.25em 0 0 #fbee8e, inset -.3125em -.3125em 0 .625em #fff5b2;
    margin-top: -.125em;
}
#theme-toggle:checked {
    font-size: 10rem;
}
#theme-toggle:checked + label {
    background-position: top;
    border-color: #5983a6;
}
#theme-toggle:checked + label span {
    background: transparent;
    transform: translateX(calc(100%)) scale(.65);
    box-shadow: inset -.1875em -.1875em 0 0 #fbe7ef, inset -.5625em -.5625em 0 0 #fffff7;
}
</style>

In the template tags, we are creating a simple html checkbox and assigning a click event to it. Inside the script tags, we are toggling “dark-mode” class to the body tag. We are also “saving” the user preference inside localstorage, so we can see the same theme mode even after page reload. The most interesting part for me is the css code, because we are actually creating the sun and the moon icons by using only custom css (no icons or images)! Now, when you check again the home page, you should see a beautiful sun icon just after the call to action button. Try to toggle it to make sure it is working. The last thing that you need to do is to add some custom css to customize your dark layout. You can easily add more styles by using the “.dark-mode” css class. Happy blogging!

Read more: