johno
Writing
Notes
Contact

Extending Components in Themes

Component Shadowing provides a powerful API for customizing the rendering of components and even entire pages. For example, changing the logo might involve shadowing that component by creating your custom implementation in a file named src/gatsby-theme-blog/components/logo.js. Now, with recent improvements shipped to Gatsby core, you can extend any component or file in the src directory.

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.

Before component extending was added this meant you had to copy over the entire component implementation from the theme to wrap it with your Card which might look something like:

import React from 'react'
import { Avatar, MediaObject, Icon } from 'gatsby-theme-blog'
import Card from '../components/card'

export default ({ name, bio, avatar, twitterUrl, githubUrl }) => (
  <Card>
    <MediaObject>
      <Avatar {...avatar} />
      <div>
        <h3>{name}</h3>
        <p>{bio}</p>
        <a href={twitterUrl}>
          <Icon name="twitter" />
        </a>
        <a href={githubUrl}>
          <Icon name="github" />
        </a>
      </div>
    </MediaObject>
  </Card>
)

It's not terrible because the component is relatively straightforward, but it wasn't the cleanest workflow to wrap a component or pass a different prop.

Importing the Shadowed Component

In the above example it'd be preferable to be able to import the Author component and wrap it with your Card.

Now, that component extending has been added you can do the following instead:

import React from 'react'
import { Author } from 'gatsby-theme-blog/src/components/author'
import Card from '../components/card'

export default props => (
  <Card>
    <Author {...props} />
  </Card>
)

This is a quick and efficient way to quickly customize rendering without needing to worry about the implementation details of the component you're looking to customize.

Applying New Props

In some cases there could be a component with different variants without an API to modify it outside of shadowing. With component extending you can import that component and then add your new prop to change it.

import { NewsletterButton } from 'gatsby-theme-blog/newsletter'

export default props => (
  <NewsletterButton {...props} variant="link" />
)

Change an Object

Another use case might be changing a theme.js file that a Gatsby Theme uses to set colors globally.

import { theme } from 'gatsby-theme-blog'

export default { ...theme, primary: 'tomato' }

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

Conclusion

If you need to make a small change to an existing component or add an additional prop extending the component you're shadowing can be a useful way to achieve it.