Implementing dark & light themes for your Gatsby website
April 22, 2020
Having a dark mode is cool
Even though a dark mode probably isn’t as good for your eyes as might think, letting the user choose between a dark and a light theme is a nice feature. The biggest driver is aesthetics : dark themed interfaces just look better in my opinion.
Other reasons are better battery life and less blue light for bedtime reading. If you’re just starting a website, it’s a good idea to implement it right away because the bigger the project gets, the harder it will be to set this up.
#1 : gatsby-styled-components-dark-mode
We are going to take advantage of gatsby plugins to make our life easier.
The first one we are going to be using is called gatsby-styled-components-dark-mode.
A Gatsby plugin that handles injecting a dark and light theme, as well as functionality for toggling between them. It also persists the state of your users’ dark option in their browsers.
Follow install and setup instructions here.
#2 : Syntax highlighting for your code blocks with PrismJS
The tricky part when implementing a dark mode are code blocks. On Brocolli, blog posts are written in Markdown, and parsed and transformed into beautiful html pages with Remark. The code blocks in your markdown file are syntax highlighted with PrismJS.
You need both those Gatsby plugins to make this solution work.
Here is the trick : you need to create custom styles for the code syntax highlighting of your dark and light themes.
For example, here are the .css
files for the light
and the dark
themes for this blog. You can download such files here.
Now, the important thing : before every selector in your dark theme .css
file, add the following selector : html[displayMode='dark']
.
.token.tag {
color: #e06c75;
}
thus becomes
html[displayMode='dark'] .token.tag {
color: #e06c75;
}
Then, in your layout file, get the current theme with useContext
:
const themeContext = useContext(ThemeManagerContext);
const displayMode = themeContext.isDark ? "dark" : "light";
and apply it to your document’s head with react-helmet:
<Helmet htmlAttributes={{ displayMode }} />
As you switch the theme on your website, the <html>
tag will be updated with the displaymode = "light"
or displaymode = "dark"
attributes, and the appropriate styling will automatically be applied.
#3 Use the dark theme by default
In your layout file :
const themeContext = useContext(ThemeManagerContext);
useEffect(() =>
themeContext.toggleDark(window.localStorage.getItem('dark') === "true"),
//the localStorage item "dark' is handled by `gatsby-styled-components-dark-mode`
[]);
#4 That’s about it
I wrote this article after reading this conversation on spectrum. The original solution comes from tetchi, check out his blog or how he implemented this on his github.
You can also have a look at the implementation of this solution on my blog here.
If you have any questions, google is your friend.
Peace out ✌️