Missive App
Published in

Missive App

Make your Electron app Dark Mode compatible

With the recent public release of macOS Mojave and as a developer, I’m sure you’ve already got a ton of requests to make a dark theme version of your app. We sure did.

We kept postponing development because of a major technical roadblock: We were using SASS variables and when it comes down to it, these are pretty much static. Or at least they are once compiled into CSS. We also didn’t want our CSS to get any bigger than it is or even deal with a different file per theme. We’re eventually looking for 100% customizable themes.

But I have good news for you, CSS Variables show a whopping 86.8% support rate. For Electron apps, that’s not even a concern 💯.

CSS Variables support | September 2018

Goal: 3 themes with minimal effort


light, dark and light-dark-sidebar are the initial themes we’re looking for. The beauty of the technique explained below is that we only need 2 base themes, the 3rd one being a mix of both and only requires one extra CSS selector.

Minimal effort

By minimal effort, not only do I mean being able to add new themes only by editing existing CSS Variables, but also from a performance perspective. The HTML is to not be made aware of the current theme and no re-rendering of any sort is to be required when changing theme.

Bonus: Quite easy to quickly debug when all you have to do is change an attribute on <html> via the web console 🐛.

The 3 main themes of Missive

We don’t want no FOUC!

What’s worse than seeing a light theme appear for a few milliseconds then switch to a dark one? Nothing 👏🏼 is 👏🏼 worse.


To avoid FOUC, we’ll use localStorage and a preloaded script on BrowserWindow. The preloaded script is loaded as soon as your app is launched and while <html> can’t be accessed yet, window can.

Using the systemPreferences API provided by Electron, we know if the OS is currently using dark mode and can subscribe to the theme change event.

Update localStorage from preload script

Then we’ll define the __setTheme function in index.html and make sure it’s called when launching the app. On the first run, the preloaded script already set localStorage.os_theme, so we can use that and set an attribute on <html> as soon as possible, especially before loading the styles. We’ll also preemptively read localStorage.user_theme in case you want to let users choose their own theme and not rely on the OS only.

Set <html> data-theme attribute


We’ll take advantage of a few techniques: CSS Variables, specificity and attribute selectors.

Theme-aware CSS Variables

Extra specificity selector [data-theme] [data-theme="light"]
That’s a way to make themes embeddable within each other. You could force any part of your app to have a given theme by setting the data-theme attribute.

Nota bene: Without that, even if you add data-theme="light" anywhere in your HTML, it would still use the <html data-theme="dark"> variables. Because for the same specificity, dark variables are being declared after in the CSS. That’s just good old cascading rules being applied.

We use that technique to dynamically create a thumbnail (HTML + CSS) of our theme variants.

Attribute selector ^="light"
That is so both light and light-dark-sidebar use the same base theme.

Scoping variables with [data-theme="light-dark-sidebar"] nav
That is to have theme variants without having to make the HTML aware of it. For that theme, the light theme is used, but the <nav> element is going to use the dark variables. That way, you don’t have to re-render any part of your HTML when changing the theme, it’s just a matter of updating the <html data-theme> and Voila!

Theme-aware CSS Variables playground

macOS Mojave

Don’t bother with transitions, even if that’s just CSS it’s 100% seamless on Mojave. macOS freezes the current frame and renders the new layout behind the scenes. When ready, it’ll crossfade the two layouts making your app look as native as Finder.

Give it a try and let us know how the dark mode feels. As you may already know our dirty little secret, you won’t be surprised to hear that this only required a full week worth of work time and a single developer to implement.

Dark theme is also available on Windows, iOS, Android and web browsers 🌒.

Missive dark theme available on all platforms




The one app for team email and chat

Recommended from Medium

From Java to …

The Infosys Interview

The First Signs of Alcoholic Liver Damage Are Not in the Liver

AWS Infrastructure Visualization with Quadzig — TechToSpeech

Environmental Variable

Effective Java in Kotlin, item 1: Consider static factory methods instead of constructors

Polis Project Weekly Updates (10/09 to 10/15)

PG — Pwned1— Walkthrough (Offensive Security Proving Grounds Play Boxes)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Etienne Lemay

Etienne Lemay

Co-founder & Developer at @missiveapp 📬

More from Medium

Visually building websites

Extending Bootstrap components using utility classes only, just like Tailwind

Vue Storefront is currently the most developer-friendly front-end option for #eCommerce projects.

The Unknowns of PWA App