The Anatomy of Dark Mode (A Craft CMS plugin)

I want to write a little about Craft Plugins from a slightly different perspective to what you might have seen previously.

There are a few great articles that describe the process of creating a plugin, but so far I haven't seen much written about specific plugins that have been created - even though I think there is a lot to be learned from the real world challenges that production ready plugins have had to face.

To address this in the capacity that's available to me, I'm going to make sure that for each plugin I create I also produce an associated 'Anatomy Of' blog post which not only covers the technical detail, but also where the idea came from, commercial concerns and future roadmap ideas.

To kick this off lets have a look at Dark Mode...

What Is Dark Mode?

Dark Mode is a simple plugin that changes the Craft control panel cosmetically - making everything that was once light, dark.

You can find it in the Craft Plugin Store.

Where Did The Idea Come From?

There are lots of applications that come bundled with a dark mode these days so the idea is far from new. There are a few benefits that you can find written about but the main two for me are:

  • Reduced eye strain - especially when the space behind your screen is dark
  • Less blue light - better for you when working at night

The specific event that prompted me to start working on the plugin was seeing this Tweet pop up in Tweet Deck:

Why Did I Decide To Build It?

A mixture of benevolent community member-ism and wanting to establish myself as a known plugin developer.

By creating something useful which I could deliver for free and support long term I'm hoping to provide a popular touch point between the Craft CMS community and myself.

The ultimate end goal is to begin offering services directly related to Craft and its ecosystem. I'm hoping that giving developers within this ecosystem a few good reasons to trust me will help in the long run.

+ Saving the earth by darkening a few pixels. Maybe?

How Does It Work?

This is a pretty simple plugin so there's no too much to talk about technically. The main function is to inject a custom stylesheet into all of the control panel pages. This is achieved using a custom Asset Bundle which is injected by the Plugin's base class as follows:

$request = Craft::$app->getRequest();
if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
    if (!Craft::$app->user->isGuest) {
        $this->view->registerAssetBundle(DarkModeAsset::class);
    }
}

The majority of the work put into this plugin was the development of the actual css which renders dark mode. I made a couple of decisions to try to make this a bit more future-proof and speed up initial development.

1) For the base of my css I stole all of the existing control panel scss files from the Craft git repo and tweaked the variables it contained to change all of the base colours.

This means that in the future if P&T add another control panel section I'll be able to just lift all of their new css files, excluding the variables definitions, and drop them into my project then rebuild. As long as their new additions are referencing the variables for their colours my new css file will magically cover all of the additions with no work needed from me.

2) Everything not caught by the above is pulled out into a separate scss file which is organised into sections. Each section contains overrides to styles which are defined in different stylesheets in the Craft CP. I.E there's a section for pluginstore.css overrides, a section for routes.css overides etc...

This helps to keep things organised and will allow me to break these into separate files in the future if I wish.

The plugin's buildchain is super boring - just an npm script which executes the cli sass compiler. I didn't even bother setting up a 'watch', but that's mainly due to laziness.

The final part of the plugin which is a little interesting is the on/off switch which remembers its state across pages. This switch is simply setting a localstorage boolean when it is toggled and simultaneously toggling a darkmode class on the body tag.

The plugin is also injecting a piece of JS into the very top of the body which looks like this:

var body = document.getElementsByTagName('body')[0];
if (localStorage.getItem('darkmode-enabled') == 'true') {
    body.classList.add('darkmode');
}

The reason that I'm forcing this to execute at the top of body rather than adding it to my Asset Bundle's js is to avoid a light mode style flash before the javascript executes. By injecting it early we can get it to run before the browser's first paint, avoiding that horrible flash.

Future Plans

Fix bugs and keep the plugin maintained. There are already a few plugins which are integrating with this plugin by making use of the darkmode class which is added to body. It would be really cool if that becomes a standard for Craft plugin developers so that everything feels lovely and integrated.


Read Next



2024 Goals
Write Things