Supercharging Gatsby with Styled-Components

Gatsby is a powerful static site generator that allows you to create blazing fast websites with React. Out of the box, Gatsby provides a fantastic development environment, a rich plugin ecosystem, and optimized production builds. One of the best parts of Gatsby is that you can easily customize and extend the default starter to fit your specific needs.

In this post, we‘ll walk through converting the Gatsby default starter to use the popular CSS-in-JS library styled-components. By the end, you‘ll have a solid understanding of how to integrate styled-components into a Gatsby project to unlock scoped styling, dynamic styling props, theming, and more.

What‘s Inside the Gatsby Default Starter

First, let‘s take a quick look at what comes with the Gatsby default starter. When you create a new Gatsby site using gatsby new, you get a simple site with a few key files and folders:

  • src/pages: Directory for page components that automatically become pages
  • src/components: Place for shared React components used across pages
  • src/images: Folder for images
  • gatsby-config.js: Configuration file for siteMetadata, plugins, etc.
  • gatsby-node.js: File where you can customize Gatsby‘s Node.js settings

The default starter also comes with a global stylesheet (layout.css) that provides some basic resets and styles. While this is a fine starting point, we can unlock more flexibility by using styled-components instead.

Why Use Styled-Components with Gatsby

Styled-components is a popular CSS-in-JS library that allows you to write actual CSS code to style your React components. Let‘s highlight a few key benefits of using styled-components with Gatsby:

  1. Scoped styles: Styles are scoped to individual components, avoiding global clashes
  2. Dynamic styling: Can adjust styles based on component props or global theme
  3. Painless maintenance: No need to manually maintain separate CSS files
  4. Enhanced readability: Styles are colocated with components, easier to understand
  5. Automatic vendor prefixing: Write modern CSS without worrying about browser support

Sold on styled-components? Great! Let‘s see how to convert the Gatsby starter.

Setting Up Styled-Components in Gatsby

To start using styled-components, we first need to install a few dependencies:

npm install gatsby-plugin-styled-components styled-components babel-plugin-styled-components

Here‘s what each one does:

  • gatsby-plugin-styled-components: Handles CSS extraction and enables server-side rendering support
  • styled-components: The actual styled-components library
  • babel-plugin-styled-components: Babel plugin for improving debugging and adding component names to generated class names

Next, update the gatsby-config.js file to include the styled-components plugin:

module.exports = {
  plugins: [
    ‘gatsby-plugin-react-helmet‘,
    ‘gatsby-transformer-sharp‘,
    ‘gatsby-plugin-sharp‘,
    // highlight-start
    ‘gatsby-plugin-styled-components‘,
    // highlight-end
  ],
}

With that, we‘re ready to start converting to styled-components!

Creating a Global Styles File

Rather than using a global CSS file like the Gatsby starter does with layout.css, we can use styled-components to create a global styles file. This is where we‘ll put any base styles or CSS resets.

Create a new file at src/theme/globalStyles.js with the following:

import { createGlobalStyle } from ‘styled-components‘;

export const GlobalStyle = createGlobalStyle`
  @import url(‘https://fonts.googleapis.com/css?family=Montserrat|Roboto‘);

  body {
    font-family: ‘Roboto‘, sans-serif; 
    margin: 0;
    padding: 0;
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: ‘Montserrat‘, sans-serif;
  }

  a {
    text-decoration: none;
    color: inherit;
  }
`;

Here we‘re using the createGlobalStyle function from styled-components to generate a GlobalStyle component. This allows us to write plain CSS that will be injected globally. In this example, we‘re importing some Google fonts, setting a default font family on the body, and customizing font styles for headings.

To use our GlobalStyle component, import it into your src/components/layout.js file and render it inside the StaticQuery:

import React from ‘react‘;
import { GlobalStyle } from ‘../theme/globalStyles‘;

const Layout = ({ children }) => (
  <StaticQuery
    // ...
    render={data => (
      <>
        <GlobalStyle />
        <div>
          {children}
        </div>
      </>
    )}
  />
);

Now any global styles will be applied consistently across all pages!

Converting Components to Styled Components

With our global styles in place, let‘s start converting individual components to use styled-components. We‘ll follow a simple process:

  1. Import styled from ‘styled-components‘
  2. Create a styled component for each element receiving custom styles
  3. Replace classNames and inline styles with props on the styled component

Here‘s an example of converting the Header component:

import React from ‘react‘;
import { Link } from ‘gatsby‘;
import styled from ‘styled-components‘;

const HeaderWrapper = styled.header`
  background: rebeccapurple;
  margin-bottom: 1.45rem;
`;

const Headline = styled.div`
  margin: 0 auto;
  max-width: 960px;
  padding: 1.45rem 1.0875rem;

  > h1 {
    margin: 0;
  }  
`;

const StyledLink = styled(Link)`
  color: white;
  text-decoration: none;
`;

const Header = ({ siteTitle }) => (
  <HeaderWrapper>
    <Headline>
      <h1>
        <StyledLink to="/">
          {siteTitle}
        </StyledLink>
      </h1>
    </Headline>
  </HeaderWrapper>
);

export default Header;

Feels much cleaner, right? We‘ve created three styled components:

  1. HeaderWrapper replaces the outer header element and styles the purple background
  2. Headline centers the inner content with a max-width and adjusts spacing
  3. StyledLink is a styled version of the Gatsby Link component for navigation

Notice how we‘re able to nest selectors like > h1 to target the h1 inside Headline. We‘ve also replaced string values like "rebeccapurple" and pixel units directly in the CSS.

You can repeat this same conversion process for other components like:

  • Layout: Create a MainWrapper, add styles to children instead of a wrapping div
  • Index/pages: Replace inline image styles with a custom ImageWrapper component

Leveraging Styled Props and Theming

One of the biggest benefits of styled-components is the ability to dynamically adjust styles based on props. For example, consider a simple Button component:

import styled from ‘styled-components‘;

const Button = styled.button`
  padding: 0.5rem 1rem;
  font-size: 1rem;
  border-radius: 4px;
  color: white;
  ${props => props.secondary ? 
    `background: seagreen` : 
    `background: rebeccapurple`
  }
`;

Here we‘re using an arrow function inside the styled block to conditionally set the background color based on a "secondary" prop. Now we can toggle between two button styles like:

<Button>Click me!</Button>
<Button secondary>Click me!</Button>

Styled-components also has theming support powered by React context. You can define a theme object with your color palette, font sizes, spacing values, etc. Then provide the theme to any styled component using the "theme" prop.

Here‘s a quick example theme file (src/theme/theme.js):

export const theme = {
  colors: {
    primary: ‘rebeccapurple‘,
    secondary: ‘papayawhip‘,
  },
  fontSizes: {
    small: ‘0.8rem‘,
    medium: ‘1rem‘,
    large: ‘1.5rem‘
  },
  spacing: {
    xs: ‘0.5rem‘,
    small: ‘1rem‘,
    medium: ‘2rem‘,
    large: ‘3rem‘
  }
}

To use the theme, wrap your app in a ThemeProvider and pass the theme object:

import React from ‘react‘;
import { ThemeProvider } from ‘styled-components‘;
import { theme } from ‘../theme/theme‘;

const Layout = ({ children }) => (
  <ThemeProvider theme={theme}>
    <GlobalStyle />
    <div>
      {children}  
    </div>
  </ThemeProvider>
);

Then access theme values in any styled component like:

const Button = styled.button`
  padding: ${props => props.theme.spacing.small}; 
  font-size: ${props => props.theme.fontSizes.medium};
  color: ${props => props.theme.colors.secondary};
`;

Theming keeps your styles consistent and makes it painless to update values app-wide.

Styling Based on Component State

Since styled-components are tied to React components, we can also dynamically update styles based on component state or lifecycle methods. For example, here‘s how we could add a hover effect to a Link component:

import styled from ‘styled-components‘;

const HoverLink = styled(Link)`
  color: black;
  transition: color 0.2s;

  &:hover {
    color: rebeccapurple;
  }
`;

The &:hover syntax will apply the hover styles when the mouse is over the link. The transition property animates the color change smoothly.

We could also use styled-components to change styles based on component state. Imagine a Collapsible component that toggles some inner content:

import React, { useState } from ‘react‘;
import styled from ‘styled-components‘;

const CollapseWrapper = styled.div`
  height: ${props => props.isOpen ? ‘auto‘ : ‘0‘};
  overflow: hidden;
`;

const Collapsible = () => {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(!isOpen)}>
        Toggle
      </button>
      <CollapseWrapper isOpen={isOpen}> 
        <h3>Some content goes here!</h3>
      </CollapseWrapper>
    </>
  );
}

Here, we‘re using the isOpen state variable to conditionally set the CollapseWrapper height. This allows the content to expand/collapse when the Toggle button is clicked.

Best Practices and Considerations

As you continue to work with styled-components, there are a few best practices and things to keep in mind:

  1. Use semantic HTML elements whenever possible (e.g. header, nav, article)
  2. Choose meaningful names for styled components (e.g. NavBar vs MyComponent)
  3. Keep complex styles in a separate "style" file to avoid cluttering your component logic
  4. Split up large Gatsby pages into smaller sub-components
  5. Memoize styled components that are rendered repeatedly for performance

The styled-components docs also provide some great tips for component-oriented design, conditional styling, and more.

Conclusion

In this post, we learned how to convert the Gatsby default starter to use styled-components. The process involves installing a few dependencies, adding the gatsby-plugin-styled-components plugin, creating a global styles file, and then methodically converting each component to CSS-in-JS.

We also explored some more advanced patterns like:

  • Using props to dynamically change styles
  • Theming with React context
  • Updating styles based on state and user interactions

By combining Gatsby and styled-components, you get the performance benefits of Gatsby with the flexibility of CSS-in-JS. It‘s a match made in heaven!

I hope this guide has been helpful in your journey to master Gatsby and styled-components. To learn more, check out the official docs for each project:

You can also find all the code from this tutorial on GitHub: https://github.com/your-username/gatsby-styled-components-example

Happy coding!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *