DEV Community

Matt Hagner
Matt Hagner

Posted on

What is Shadowing in Gatsby Themes?

This is the continuation of a series on Gatsby themes. In previous posts we covered how to start a Gatsby site from scratch, how to add a theme, and how to use theme options to customize our website.

We'll be picking up with Shadowing in Gatsby which is a powerful concept that allows you to use themes and customize only the parts that you want in a reliable, ergonomic way.


What is Shadowing?

Shadowing is Gatsby's answer to customizing parts of a theme, without throwing the baby out of the bathwater. It would suck if you needed to re-wire gatsby-theme-blog from scratch if you wanted to change some of the styles, components, or content.

It would also suck to have a giant object with theme options for everything you want a user to be able to override. It would also suck if some theme creator made some component, or style NOT overridable.

By making shadowing an inherent part of how Gatsby works, there is a consistent and simple way to override pretty much anything.

What can you Shadow?

With Gatsby themes you can shadow styles, components, and data requirements (GraphQL queries). Anything that lives in the src directory of a theme is fair game!

How do you Shadow?

Let's quickly change something small like the main color of our blog. I love purple, but you know what's an even better color? Tomato.

To shadow something from a theme we follow a simple convention. Inside of our src folder, we make a folder with the theme name, gatsby-theme-blog, and then we mimic the path to the file in the theme itself but we ignore the src inside of the theme.

So gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors.js becomes src/gatsby-theme-blog/gatsby-plugin-theme-ui/colors.js.

Since we happen to want to change a color, and I happen to know that gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors.js is the exact file that we need to shadow, we need to create some folders, and a new file in our Gatsby website so we can shadow it.

mkdir -p src/gatsby-theme-blog/gatsby-plugin-theme-ui
touch src/gatsby-theme-blog/gatsby-plugin-theme-ui/colors.js

Now pop open your favorite code editor and we are going to open up two files. File 1) node_modules/gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors.js and file 2) src/gatsby-theme-blog/gatsby-plugin-theme-ui/colors.js.

When I'm shadowing, I find it easiest to look at the thing I'm going to shadow, while working on the new file.

Your node_modules/gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors.js file should look something like this:

const purple60 = `#663399`
const purple30 = `#D9BAE8`
const grey90 = `#232129`
const black80 = `#1B1F23`
const white = `#fff`
const lightWhite = `rgba(255, 255, 255, 0.86)`
const opaqueLightYellow = `rgba(255, 229, 100, 0.2)`
const opaqueLightWhite = `hsla(0, 0%, 100%, 0.2)`
const lightGray = `hsla(0, 0%, 0%, 0.2)`

export default {
  text: grey90,
  background: white,
  primary: purple60,
  secondary: black80,
  muted: lightGray,
  highlight: opaqueLightYellow,
  heading: grey90,
  prism: {
    background: `#011627`,
    comment: `#809393`,
    string: `#addb67`,
    var: `#d6deeb`,
    number: `#f78c6c`,
    constant: `#82aaff`,
    punctuation: `#c792ea`,
    className: `#ffc98b`,
    tag: `#ffa7c4`,
    boolean: `#ff5874`,
    property: `#80cbc4`,
    namespace: `#b2ccd6`,
    highlight: `hsla(207, 95%, 15%, 1)`,
  },
  modes: {
    dark: {
      text: lightWhite,
      background: grey90,
      primary: purple30,
      secondary: lightWhite,
      muted: opaqueLightWhite,
      highlight: purple60,
      heading: white,
    },
  },
}

The color that we want to change is the primary key in the object.

export default {
  text: gray90,
  background: white,
  primary: purple60,
  //...
}

So what can we learn from this file? The first thing to take away is that we should have a default export in our shadowed colors.js file. The second is that, unless we want to change a bunch of these values, we will need some way to merge the gatsby-theme-blog colors, with our colors and just override the ones that we want to.

Before we get to figuring out how to merge our colors object, let's make an export default and set the primary key to 'tomato'.

export default {
  primary: 'tomato',
}

Now the cool part...

import colors from 'gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors'

export default {
  ...colors,
  primary: 'tomato',
  modes: {
    dark: {
      ...colors.modes.dark,
      primary: '#ff755e'
    }
  }
}

We can import the thing we are shadowing and use whatever JavaScript method we want to merge, and override whatever we want. It's that easy. At least updating styles is that easy.

Why does Shadowing work this way?

When you are using a theme Gatsby first tries to resolve within your own projects src folder, looking in src/{theme-name}/{any-sub-dirs}/{file}, if it doesn't see anything there, it resolves to node_modules/{theme-name}/src/{any-sub-dirs}/{file}.

When building a theme you don't have to do anything special to allow shadowing. It just works. When you're consuming a theme you can follow these conventions to shadow whatever you need to.

BONUS

Want an even easier way to do partial/deep updates of an object in JavaScript? There's a really cool library called immer that is particularly good at this.

Just install immer to the project, import it into our file and let the magic happen.

import produce from 'immer'
import colors from 'gatsby-theme-blog/src/gatsby-plugin-theme-ui/colors'

export default produce(colors, draft => {
  draft.primary = 'tomato'
  draft.modes.dark.primary = '#ff755e'
})


Conclusion

Shadowing is a concept in Gatsby that allows us to override and compose styles, components, and data from a Gatsby theme. It follows a simple convention of path resolution to allow shadowing. Anything in a theme's src/ folder is open to shadowing.

Next Up

Next time we will dive into shadowing gatsby-theme-blog and making it our own by shadowing styles and components.

Top comments (0)