We're refactoring our in-house CRM in Vue as a Nuxt app, and since it's 2019, I wanted to support Dark Mode across the entire application with as little effort as possible.
Dark Mode is widely supported in Safari, Firefox, and Chrome by now, and a lot can be done on any web app with just CSS and CSS variables. 90%+ of my Dark Mode styling is just done in CSS, as it should be.
But if you're using a framework like Vue, you're probably controlling some styles of your components directly with props instead of just relying on CSS classes, like so:
/* Normal button for light mode */
<sui-button primary icon="plus">New entity</sui-button>
/* Inverted button for dark mode */
<sui-button primary inverted icon="plus">New entity</sui-button>
I'm using Semantic UI for my buttons which is… fine for now. If I pass inverted="true"
(shortened to simply inverted
here), I get my Dark Mode-friendly button.
To turn that boolean into a globally accessible variable in my Nuxt app, a Vuex store seems like the right decision:
/* store/const.js */
export const state = () => ({
darkMode: false
});
export const mutations = {
setDarkMode: state => {
state.darkMode = true;
},
unsetDarkMode: state => {
state.darkMode = false;
}
};
export const actions = {
setDarkMode: ({ commit }) => commit("setDarkMode"),
unsetDarkMode: ({ commit, state }) => state.darkMode && commit("unsetDarkMode")
};
Assuming you have some Dark Mode media query styles set up, checking for Dark Mode and listening to changes is something we can do in our layout file:
/* layouts/default.vue */
<template>
<nuxt />
</template>
<script>
export default {
components: {
AdminNav
},
data() {
return {
mql: window.matchMedia('(prefers-color-scheme: dark)')
}
},
created() {
this.darkMode(this.mql)
this.mql.addListener(this.darkMode)
},
beforeDestroy() {
this.mql.removeListener(this.darkMode)
},
methods: {
darkMode: function(e) {
if (e.matches) {
return this.$store.dispatch('const/setDarkMode')
}
return this.$store.dispatch('const/unsetDarkMode')
}
}
}
</script>
Finally, fetching the boolean in any component that needs it is just a computed property away:
/* components/myComponent.vue */
<template>
<sui-button primary inverted="darkMode" icon="plus">New entity</sui-button>
</template>
<script>
export default {
computed: {
darkMode() {
return this.$store.state.const.darkMode
}
}
};
</script>
Now I get that nice inverted button flavor when using Dark Mode. Yum 😋.
Top comments (0)