First of all.
The following idea can be applied to all kinds of sites while those use React, you need to know that Gatsby is a React-based open-source framework for creating websites and apps.
The main Idea π‘
We need to know that themes are CSS properties that change when we select a specific theme. eg.
          <button type="button" onClick={handleToggle} style={styles(theme).toggle}>
            { theme === themes.light ? 'β½' : 'βΌ' }
          </button>
We will create a dark β½ and light  βΌ theme:
import { createContext, useState } from 'react'
export const themes = {
  light: {
    foreground: 'rebeccapurple',
    background: 'white'
  },
  dark: {
    foreground: 'white',
    background: 'rebeccapurple'
  }
};
export const ThemeContext = createContext();
We need to create also the hook to manage the state of the current theme:
export const useThemes = () => {
  const [mode, setMode] = useState(themes.light);
  const toggleMode = () => { 
    if (mode === themes.light) {
      setMode(themes.dark);
    } else {
      setMode(themes.light);
    }
  };
  return [mode, toggleMode]
};
Please create a context to wrap your app :
import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import { ThemeContext, themes, useThemes } from './Context/Theme'
import Header from "./Header"
import "./layout.css"
const Layout = ({ children }) => {
Import and create only one instance of our theme, this is a kind of singleton pattern.
  const [theme, handleToggle ] = useThemes();
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
console.log(theme.foreground);
  return (
    <ThemeContext.Provider value={themes}>
      <Header siteTitle={data.site.siteMetadata.title} handleToggle={handleToggle} theme={theme}/>
      <div
        style={{
          color: theme.foreground,
          background: theme.background,
          margin: `0 auto`,
          maxWidth: 960,
          padding: `10rem 1.0875rem 1.45rem`,
        }}
      >
        <main>{children}</main>
        <footer>
          Β© {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.org">Gatsby</a>
        </footer>
      </div>
    </ThemeContext.Provider>
  )
}
Layout.propTypes = {
  children: PropTypes.node.isRequired,
}
export default Layout
The Header component will look like:
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React, { useContext } from "react"
import {styles} from './styles'
import { ThemeContext } from "../Context/Theme";
I will use Context to compare what is the current theme and
handleTogglefunction to change between themes.
function Header({ siteTitle, handleToggle, theme }) {
  const themes = useContext(ThemeContext);
  return (
    <header
      style={styles(theme).header}
    >
      <div
        style={styles(theme).navbar}
      >
        <h1 style={styles(theme).title}>
          <Link
            to="/"
            style={styles(theme).link}
          >
            {siteTitle}
          </Link>
        </h1>
        <div style={styles(theme).buttonContainer}>
          <button type="button" onClick={handleToggle} style={styles(theme).toggle}>
            { theme === themes.light ? 'β½' : 'βΌ' }
          </button>
        </div>
      </div>
    </header>
  );
}
Header.propTypes = {
  siteTitle: PropTypes.string,
}
Header.defaultProps = {
  siteTitle: ``,
}
export default Header
Wrapping up
The main idea is to know that you can apply this to any site ;)
              
    
Top comments (4)
Hi, I used the same way to build my theme, however, the children component inside couldn't get ThemeContext... Do you know how to solve it?
Hi! Could you please show me a snippet of code?
Maybe you have to assign some css classes to the children
Hi, I found the solution. Before, I wrapped ThemeContext inside layout
Then in my page Blog, I coudln't get themeContext
The solution is to create a wrapRootElement in gatsby-browser.js. Then all pages could get ThemeContext's value.
Also look that I only themed the Header component, Main and Footer components need the prop theme or reach themes via useContext