With the arrival of Mojave, Apple introduced system-wide dark mode. Dark mode transforms your interface and a bunch of Apple apps into a dark version. As a big fan of dark mode, I wanted to jump on the trend and created a dark mode toggle for the Passenger Docs.

darkmode

So why Dark Mode?

Because it’s cool.
(And I guess it creates a working environment that causes less strain on the eyes, especially when you are already using dark mode for your other apps. But mostly because it makes you feel like Batman.)

Designing a Dark Mode interface

I recommend to not simply design a black background with white text on it, or inverse your color scheme without further finetuning. The reason you don’t want to make your interface fully black is because it becomes too overpowering. And not only that, full white text on black causes a lot of strain on the eyes when you are reading for a long time, which defeats the purpose of dark mode.

Screenshot-2018-11-28-at-15.04.25

You’ll find out that once you make your black a little lighter and your text a little darker, it starts to relieve some strain on your eyes.

Since we’re heading into shades of gray now, I recommend to add a hint of color to it, just gray can become quite stale.

Now that we have some designing out of the way, let’s move on to smoothly rendering dark mode for your user.

Smoothly rendering dark mode without using frameworks/libraries

If you’re using React, you can easily use a lifecycle method to make sure your DOM renders with the right styles. But what if you’re not using any frameworks or libraries? Here’s how I did it:

Once the user turns on dark mode, it will get stored into localStorage to make sure their selection is saved. The script will add a dark-mode class to the body when dark-mode exists in localStorage.

This introduces some usability problems because now when the DOM gets rendered, it will get rendered in light mode and then quickly switch to dark mode. The same goes for the mode selector which gets rendered unchecked, only to be checked once it loads the script.

So how to solve this? First I rendered the input with Javascript so it doesn’t render an 'unchecked' version of the toggle button.

someContainer.insertAdjacentHTML(‘afterbegin’, `
  <label class="switch">
    <input type="checkbox">
    <span class="slider round"></span>
  </label>
`)

Then, in order to render your body with dark-mode without seeing the light-mode first, you’ll want to load a script right after the tag that checks the localStorage and then adds the dark-mode class to the body.

<body>
  <script>
     var body = document.querySelector('body')
      
     if (localStorage.getItem('screen_mode')) {
        body.classList.add('dark-mode')
     }
  </script>
  // content

This might not be the prettiest way to load your Javascript, but it does smoothly render your dark mode class without any visual interruptions. Another way would be to display: hide the <body> tag and show it with Javascript after. Whichever ugly method you prefer.

All in all it’s quite simple to create a dark mode toggle for yourself. For those that don’t feel like doing that, I created a simple Node package that you can use.