## Gatsby Change Color Mode With Theme UI

_May 17th 2020_

Theme UI is a JavaScript library for creating constraint-based user interfaces. It has a number of advantages over vanilla CSS because of the dynamic JavaScript layer that allows intelligent component styling. The Theme UI library also comes with some React hooks that makes theming in React a breeze. Today we’re going to walk through dynamically changing the color mode of your theme on the fly by clicking a button so cycle through all of your theme’s color modes.

### Gatsby Plugin Theme UI

Theme UI requires a custom `theme` object that will be passed in as the value to the `<ThemeProvider>` which wraps your gatsby project. Fortunately, there is a gatsby plugin `gatsby-plugin-theme-ui` that handles the context and theme provider for us. Once installed all we have to do is supply an exported object in our `./src/gatsby-plugin-theme-ui/index.js` file and the component shadowing will use our `theme` object that we export as the **context value** for the `<ThemeProvider>` component. We can first install the plugin:

```
yarn add gatsby-plugin-theme-ui
```

Once installed we need to tell gatsby to use this plugin by opening up our `gatsby-config.js` file and adding:

```
module.exports = {
  ...
  plugins: [\
    `gatsby-plugin-theme-ui`\
  ]
  ...
}
```

Now we can also create a file located at `./src/gatsby-plugin-theme-ui` called `index.js` and inside we can export an object:

```
export default {
  fonts: {
    body: 'system-ui, sans-serif',
    heading: '"Avenir Next", sans-serif',
    monospace: 'Menlo, monospace',
  },
  colors: {
    text: '#000',
    background: '#fff',
    primary: '#33e',
  },
}
```

This will export our `theme` object so our gatsby site will use this object as our **theme specification** values in our project. You can learn more about **theme specification** for declaring your `theme` object here: [https://theme-ui.com/theme-spec](https://theme-ui.com/theme-spec).

### Theme UI Color Modes

Theme UI allows for **Color Modes**. Color modes can be used to create a user-configurable _dark mode_ or any number of other color modes. You can create a _color mode_ by adding a **modes** object to our `colors` property of our theme definition. In our example let’s add a **dark** mode which is the inverse of the “default” light mode:

```
export default {
  fonts: {
    body: 'system-ui, sans-serif',
    heading: '"Avenir Next", sans-serif',
    monospace: 'Menlo, monospace',
  },
  colors: {
    text: '#000',
    background: '#fff',
    primary: '#33e',
    modes: {
      dark: {
        text: '#fff',
        background: '#000',
        primary: '#cc1'
      }
    }
  },
}
```

We can also set the _default_ name of our initial color mode so we can reference it in our **setColorMode** hook which we will define later. We can set the _default_ name by adding `initialColorModeName` property to our theme definition:

```
export default {
  initialColorModeName: 'light',
  fonts: {
    body: 'system-ui, sans-serif',
    heading: '"Avenir Next", sans-serif',
    monospace: 'Menlo, monospace',
  },
  colors: {
    text: '#000',
    background: '#fff',
    primary: '#33e',
    modes: {
      dark: {
        text: '#fff',
        background: '#000',
        primary: '#cc1'
      }
    }
  },
}
```

Now we essentially have “two” color modes in our theme: a `light` color mode and a `dark` color mode. We can toggle between these two modes by opening our `layout.js` file and importing the `useColorMode` hook from the `theme-ui` library. Initializing the hook we will obtain the current **colorMode** which will default to the `initialColorModeName` that we set in our `./src/gatsby-plugin-theme-ui/index.js` file which evaluates to `light`. We can toggle the color mode between our default `light` mode and our `dark` mode by running a ternary conditional:

```
const nextColorMode = colorMode === 'light' ? 'dark' : 'light'
```

We can use the `nextColorMode` variable and the `setColorMode` hook to toggle between the color modes:

```
/**
 * Layout component that queries for data
 * with Gatsby's useStaticQuery component
 *
 * See: https://www.gatsbyjs.org/docs/use-static-query/
 */

import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import { useColorMode } from 'theme-ui'

import Header from "./header"

const Layout = ({ children }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
  const [colorMode, setColorMode] = useColorMode()

const nextColorMode = colorMode === 'light' ? 'dark' : 'light'

return (
    <>
      <h3>Color Mode is: {colorMode}</h3>
      <button onClick={ e => {
        setColorMode(nextColorMode)
      }}>
        Change color mode
      </button>
      <Header siteTitle={data.site.siteMetadata.title} />
      <div>
        <main>{children}</main>
        <footer>
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.org">Gatsby</a>
        </footer>
      </div>
    </>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
```

### Adding More Color Modes

We can add more theme **color modes** to our `./src/gatsby-plugin-theme-ui/index.js` file:

```
export default {
  initialColorModeName: 'light',
  fonts: {
    body: 'system-ui, sans-serif',
    heading: '"Avenir Next", sans-serif',
    monospace: 'Menlo, monospace',
  },
  colors: {
    text: '#000',
    background: '#fff',
    primary: '#33e',
    modes: {
      dark: {
        text: '#fff',
        background: '#000',
        primary: '#cc1'
      },
      tomato: {
        text: '#565656',
        background: 'tomato',
        primary: 'tomato',
      },
      deep: {
        text: 'hsl(210, 50%, 96%)',
        background: 'hsl(230, 25%, 18%)',
        primary: 'hsl(260, 100%, 80%)',
      },
    }
  },
}
```

Now we have four **color modes**: our _default_ mode which is the `initialColorModeName` set to `light` and the three others defined in our **modes** object: `dark`, `tomato` and `deep`. Now we can get all color modes by desctructuring the `initialColorModeName` from the `useTheme` hook and destructuring all of the `modes` and storing all of the mode keys in a variable called `modeKeys` making sure we add in our `initialColorModeName` as the first key to our array. Next, we can iterate over the array in a `<select>` element creating `<option>` elements for each key in our array. Finally, we can bind the `onChange` handler of our `<select>` to invoke the `setColorMode` function provided by the `useColorMode` hook:

```
/**
 * Layout component that queries for data
 * with Gatsby's useStaticQuery component
 *
 * See: https://www.gatsbyjs.org/docs/use-static-query/
 */

import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import { useThemeUI, useColorMode } from 'theme-ui'

import Header from "./header"

const { theme: { initialColorModeName, colors: { modes } } } = useThemeUI()
  const modeKeys = Object.keys(modes)
  const allModes = [initialColorModeName, ...modeKeys]

return (
    <>
      <h3>Color Mode is: {colorMode}</h3>
      <select onChange={ e => {
        setColorMode(e.target.value)
      }} value={colorMode}>
        { allModes.map(mode => (
          <option value={mode} key={mode}>{ mode }</option>
        ))}
      </select>
      <Header siteTitle={data.site.siteMetadata.title} />
      <div>
        <main>{children}</main>
        <footer>
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.org">Gatsby</a>
        </footer>
      </div>
    </>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
```

### Result of Multiple Color Modes

We have successfully created a “color mode picker” that toggles between all of the color modes defined in our `theme` object definition in `./src/gatsby-plugin-theme-ui/index.js` file. We can extend this example by adding more themes! Hopefully this helps put a creative spin on your next Gatsby project!
