Gatsby Plugin Dark Mode
A Gatsby plugin which handles some of the details of implementing a dark mode theme.
29th July 2022
Time to read: 1 min
Overview
- 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
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.
ThemeToggle Component
import React from 'react'
import { ThemeToggler } from 'gatsby-plugin-dark-mode'
// use an icon of choice
import { FaYinYang } from 'react-icons/fa'
const ThemeToggle = () => {
return (
<ThemeToggler>
{({ theme, toggleTheme }) => {
if (theme == null) return null
return(
<label className='cursor-pointer'>
<input
type="checkbox"
hidden
onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')}
checked={theme === 'dark'}
/>{' '}
<span>
<FaYinYang title="Toggle Mode" className={`transition ${theme === 'light' ? "rotate-180" : "rotate-0" }`} />
</span>
</label>
)}
}
</ThemeToggler>
)
}
The toggled theme will be persisted across visits in localStorage.theme
.
Add to Navigation
import ThemeToggle from '../themetoggle/'
<ul>
<li>
<Link to="/" activeClassName="active">
Home
</Link>
</li>
// other links
<li className='flex items-center'>
<ThemeToggle />
</li>
</ul>
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>
)
}
}