How to Add a Dark Mode Toggle to a Jekyll Site

Adding a dark mode switch to a blog made with a static site generator such as Jekyll or Hugo is surprisingly simple. What’s odd is that I haven’t seen any themes that incorporate a toggle. Until that changes, it’s still relatively straightforward to implement a dark mode switch yourself.

My requirements for a dark mode switch

  1. A true switch. Sometimes I prefer light mode, sometimes dark. I didn’t want a theme that was always dark.
  2. Everything has to be client side. This is a static site. There’s no server to run scripts on. Big sites like Slack and Twitter use server side magic to serve up a dark mode.
  3. No cookies or local storage. The EU cookie banner is annoying, and private browsing can break this option.
  4. Consistency. If I’m in dark or light mode, I should never leave it unless I click on the mode switcher.

Dark mode CSS

The first step is to create a dark mode CSS. Some people use JavaScript to add a dark mode class. I prefer to have a completely separate stylesheet. Jekyll’s SASS support makes this easy.

I have a file with with all of my CSS rules in my _includes folder. I then have separate Sass files for both light and dark modes. Each file contains only variables and and an {% include css.sass %}.

URL parameters to the rescue

The URL parameter ?darkmode triggers the dark mode stylesheet to load instead of the default light mode. A bit of Javascript adds or removes ?darkmode from internal links to make sure readers don’t inadvertently leave their preferred mode.

Add an ID to the stylesheet in the page <head> so you can change the stylesheet with JavaScript:

<link id="CSS" rel='stylesheet' type='text/css' href='/css/style.css'>

Don’t leave the href attribute blank. Otherwise your page will load with no CSS at all if JavaScript is disabled.

This is my mode switch in <nav> menu:

<a href='' id='colorChanger'></a>

The link text empty so that it won’t appear if JavaScript is disabled.

Then I added this script to the end of each page:

CSS-only solutions are just out of reach

All of the above code will be moot once CSS media queries catch up with the popularity of dark themes. FireFox and Safari already have. We’re waiting on you, Chrome—yet one more reason not to embrace the Chrome monoculture.

Using local storage

Most of the initial feedback I’ve received has focused on the drawbacks of using URL parameters instead of local storage. C’mon! this is a low traffic personal blog. I can’t think of a better place to experiment.

The benefit of using URL parameters is that if you share a link in dark mode, that’s the version that will open up. If you bookmark dark mode, that’s the only version you’ll see regardless of whether you’re using private browsing or not. I admit this is idiocentric, but that’s how I browse the web.

Flavio Copes has a good tutorial for setting up a theme switcher using local storage if that’s the rout you decide to go. When I tested his solution, I still got black flashes while navigating between light mode pages.

Just a start

I don’t pretend to be a JavaScript ninja. I’m a hobbyist that likes the JAM stack and giving ‘static’ sites a dynamic feel with things random post links.

A bit of tinkering could optimize the load time of the main script: Move everything except the link changing loop to the front of the page.

This is a start. Being able to switch back and forth between light and dark themes gives a site an accessibility and UX boost. I hope this will someday be standard across blogging platforms and site generators.