Skip to content
A Gatsby plugin which handles some of the details of implementing a dark mode theme
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
.babelrc
.gitignore
LICENSE.md
README.md
gatsby-ssr.js
package.json

README.md

gatsby-plugin-dark-mode

A Gatsby plugin which handles some of the details of implementing a dark mode theme.

It provides:

  • Browser code for toggling and persisting the theme (from Dan Abramov's overreacted.io implementation)
  • Automatic use of a dark mode theme (via the prefers-color-scheme CSS media query) if you've configured your system to use dark colour themes when available.
  • A React component for implementing theme toggling UI in your site.

Install

npm install gatsby-plugin-dark-mode
// gatsby-config.js

module.exports = {
  plugins: ['gatsby-plugin-dark-mode'],
}

How to use

Implement theme toggling UI

The plugin module exports a ThemeToggler component which takes a children render prop, providing the current theme name and a toggleTheme function to change the theme.

Here's an example of using ThemeToggler with a checkbox to toggle the theme:

import React from 'react'
import { ThemeToggler } from 'gatsby-plugin-dark-mode'

class MyComponent extends React.Component {
  render() {
    return (
      <ThemeToggler>
        {({ theme, toggleTheme }) => (
          <label>
            <input
              type="checkbox"
              onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')}
              checked={theme === 'dark'}
            />{' '}
            Dark mode
          </label>
        )}
      </ThemeToggler>
    )
  }
}

The toggled theme will be persisted across visits in localStorage.theme.

Implement theming

The default theme names are 'light' and 'dark' - the plugin adds the current theme name to the <body> element's className, so you can use global styles to implement theming.

A nice option is to use CSS variables like so:

/* global.css */

body {
  --bg: white;
  --textNormal: #222;
  --textTitle: #222;
  --textLink: blue;
  --hr: hsla(0, 0%, 0%, 0.2);

  background-color: var(--bg);
}

body.dark {
  -webkit-font-smoothing: antialiased;

  --bg: darkslategray;
  --textNormal: rgba(255, 255, 255, 0.88);
  --textTitle: white;
  --textLink: yellow;
  --hr: hsla(0, 0%, 100%, 0.2);
}

You can then use these variables in your site's components...

class Layout extends React.Component {
  render() {
    return (
      <div
        style={{
          backgroundColor: 'var(--bg)',
          color: 'var(--textNormal)',
          transition: 'color 0.2s ease-out, background 0.2s ease-out',
        }}
      >
        ...
      </div>
    )
  }
}

...and in your Typography config if you're using gatsby-plugin-typography, which is included in the Gatsby Starter Blog:

// typography.js

import './global.css'

import Typography from 'typography'
import Wordpress2016 from 'typography-theme-wordpress-2016'

Wordpress2016.overrideThemeStyles = () => ({
  a: {
    color: 'var(--textLink)',
  },
  // gatsby-remark-autolink-headers - don't underline when hidden
  'a.anchor': {
    boxShadow: 'none',
  },
  // gatsby-remark-autolink-headers - use theme colours for the link icon
  'a.anchor svg[aria-hidden="true"]': {
    stroke: 'var(--textLink)',
  },
  hr: {
    background: 'var(--hr)',
  },
})

Acknowledgements

The theme detecting/switching/persistence code and the suggested theming implementation are entirely from the implementation of overreacted.io by Dan Abramov - I'm just publishing them as a plugin to make them easier to use in my own blog, and for reuse by others.

MIT Licensed

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.