You often feel the unsettling flash of a bright phone screen while relaxing in a dimly lit room. This is alleviated by introducing a "dark mode" which switches background and foreground colors to reduce eye strain. I decided to add this to my boutique web agency Laccadive IO's new Gatsby-based site.
— Heydon Pickering
One of the few types of alternative theme that adds real value to users is a low light intensity “night mode” theme. Not only is it easier on the eyes when reading in the dark, but it also reduces the likelihood of migraine and the irritation of other light sensitivity disorders. As a migraine sufferer, I’m interested!
In considering the different ways to implement this a natural fit become apparent: React’s new Context API. Having worked with Context API before, this seemed like a particularly well suited use for this API. However, I soon realized I would need to do a little set-up work to get this up and running.
After a brief search, I came across just what I was looking for, the Gatsby Browser APIs. Specifically, the
wrapRootElement API was a perfect fit for this use case. This API allows you to wrap your root element with a wrapping component, e.g. a
Provider from Redux or… a ThemeProvider from React Context. Using this, I managed to achieve dark mode for my use case.
Let's do a deep dive into how this feature was actually implemented step by step using React Context, Gatsby, and a Theme Provider to implement a dark mode UI!
Creating the Context file in a new Gatsby project
First of all, you have to initialize a Gatsby project and start it in develop mode.
- gatsby new gatsby-dark-mode
- cd gatsby-dark-mode
- npm start
Then, create a
context folder within src and the
ThemeContext.js file within it.
React.createContext is a new function in React 16.3 and allows you to create a Context object. It accepts a default state, the value which will be used when a component does not have a matching Provider above it in the tree. The function returns an object with Provider and Consumer properties which we will be using later.
ThemeProvider component which wraps its children with
ThemeContext.Provider. This component is exported as a named export from the file.
toggleDark function gets the current
state.dark value and switches the value to the opposite. It then stores the new value in
localStorage before setting it back to state using the
setState function, so that it persists over page refreshes. The dark value from
state and the
toggleDark function are passed to the Provider.
Modifying the Gatsby Browser file
Next, write the following code within the
gatsby-browser.js file, which is in the root folder in a Gatsby project:
ThemeProvider component exported from the
ThemeContext.js file wraps the root element and is exported as
wrapRootElement. This API is then invoked appropriately by the Gatsby API runner.
Editing the Layout file
layout.js uses a
<staticQuery> and renderProp to render the layout, which is wrapped by a Fragment
<>. Modify it to look like this:
The class of the wrapper div will change based on the context value of the dark variable, which we set as state in the
Adding the switch in the Header
With this configuration completed, we can now add the actual switch to toggle dark mode. Modify the
header.js component, like so:
At this point, we've set up a dark mode toggle and conditionally render a
className if dark mode is enabled. However, we still need to actually style based upon this conditional
className. As such, we need to add the following styles in the
In just a few, simple steps we've enabled a conditional dark mode that our users will certainly appreciate. We've leveraged APIs like
Context in React, as well as internal Gatsby APIs to wrap our code with a provider. Now if you visit
http://localhost:8000/ you can see all of our work pay off!
We covered the following in today’s article:
- Introduction to dark mode in web development
- Initializing a Gatsby project
- Initializing the context object with
- Using the Gatsby Browser API and returning
- Wrapping the JSX within
layout.jswith a Context Consumer and a div with class referring to the dark mode state
- Adding the switch inside the header
- Adding the styles relevant to the Dark mode
Interested in seeing this in action? Head over to https://github.com/m-muhsin/gatsby-dark-mode and clone or fork my project.