Skip to main content

Shadowing in Gatsby Themes

Gatsby themes introduce a concept called “shadowing”. This feature allows users to replace a file in the src directory that is included in the webpack bundle with their own implementation. This works for React components, pages in src/pages, JSON files, TypeScript files, as well as any other imported file (such as .css) in your site.

A practical use case is when you’ve installed gatsby-theme-blog and want to customize the author Bio component to add your own biographical content. Shadowing lets you replace the theme’s original file, gatsby-theme-blog/src/components/bio.js, with your own file to make any changes you need.

Shadowing example

If you’ve installed gatsby-theme-blog you’ll notice that it renders a Bio component which is used in the BlogPost template. If you’d like to change the Bio component you can do so with the shadowing API.

Theme file structure

You can inspect gatsby-theme-blog’s file structure to determine the file path for the file you want to shadow.

Customizing the Bio component

In this case, the file to shadow is gatsby-theme-blog/src/components/bio.js.

The shadowing API uses a deterministic file structure to determine which component will be rendered. In order to override the Bio component in gatsby-theme-blog, create a file named user-site/src/gatsby-theme-blog/components/bio.js.

Any file that lives in the src/gatsby-theme-blog directory of the user’s site will be used instead of a file with the same name located in the theme’s src directory: gatsby-theme-blog/src. This replaces the entire file: to re-use parts of the original file from the theme such as functionality or styling, check out the sections of this doc on extending and importing shadowed files.

This means that user-site/src/gatsby-theme-blog/components/bio.js will be rendered in place of gatsby-theme-blog/src/components/bio.js:

A successful shadow of the Bio component will result in the following directory tree:

Shadowing other files

Some themes, including gatsby-theme-blog, install additional plugins. gatsby-theme-blog uses gatsby-plugin-theme-ui with the gatsby-theme-ui-preset preset. Shadowing is one way to customize the styling of a theme.

For example, to shadow index.js from gatsby-plugin-theme-ui, create a file named user-site/src/gatsby-plugin-theme-ui/index.js. The styles in this file will be automatically merged with those in gatsby-theme-ui-preset. For conflicting styles, your local shadowed settings take precedence.

Note that any styles in shadowed files will automatically get deep-merged with your preset theme. Shadowed styles take precedence.

Which will result in the following directory tree:

Any source file is shadowable

The shadowing API isn’t restricted to React components; you can override any JavaScript, Markdown, MDX, or CSS file in the src directory. This gives you fine-grained control of all functionality, content, and styling that a theme provides.

If you wanted to shadow a CSS file in gatsby-theme-awesome-css that’s found at src/styles/bio.css you can do so by creating user-site/src/gatsby-theme-awesome-css/styles/bio.css

The theme’s bio.css file would then be replaced with your new CSS file.

File extensions can be overridden

As long as the theme author imports components/files without the file extension, users are able to shadow these with other types of files. For example the theme author created a TypeScript file at src/components/bio.tsx and uses it in another file:

You’ll be able to shadow the Bio file by creating e.g. a JavaScript file at src/gatsby-theme-blog/components/bio.js as the file extension wasn’t used in the import.

Extending shadowed files

In addition to overriding files, you can extend shadowable files.

This means that you can import the component you’re shadowing and then render it. Consider a scenario where you have a custom Card component that you want to wrap the author’s bio in.

Without extending the component, you would have to manually copy over the entire component implementation from the theme to wrap it with your custom shadowed component. It might look something like:

This workflow isn’t too bad, especially since the component is relatively straightforward. However, it could be optimized in scenarios where you want to wrap a component or pass a different prop without having to worry about the component’s internals.

Importing the shadowed component

In the above example it might be preferable to be able to import the Bio component and wrap it with your Card. When importing, you can do the following instead:

This is a quick and efficient way to customize rendering without needing to worry about the implementation details of the component you’re looking to customize. Importing the shadowed component means you can use composition, leveraging a great feature from React.

Applying new props

In some cases components offer prop APIs to change their behavior. To extend a component you can import it and then add a new prop.

For example, if NewsletterCTA accepts a variant prop which changes the look and colors of the call to action, you can use it when you extend the component. Below, NewsletterCTA is re-exported and variant="link" is added in the shadowed file to override its default value.

Using the CSS prop

In addition to passing a different prop to a component you’re extending, you might want to apply CSS using the Emotion CSS prop. This will allow you to change the styling of a particular component without changing any of its functionality.

Note: For this approach to work NewsletterCTA has to accept a className property to apply styles after the CSS prop is transformed by the Emotion babel plugin.

This provides a nice interface to extend an object if you want to change a couple values from the defaults.

How much shadowing is too much shadowing?

If you find yourself shadowing a large number of components in a particular theme, it might make sense to fork and modify the theme instead. The official Gatsby themes support this pattern using a set of -core themes. For example, gatsby-theme-blog relies on gatsby-theme-blog-core so you can fork gatsby-theme-blog (or skip it completely) to render your own components without having to worry about dealing with any of the page creation or data sourcing logic.

Edit this page on GitHub