Gatsby WordPress Starter Part 2: Working with Layout and Header Components

Note: This post is part of Learning Decoupling Gatsby WordPress series. This learning post is still in active development and updated regularly.

In the previous Part 1 of Learning Decoupling Gatsby WordPress series, installation of WordPress and Gatsby Source WordPress starter sites, required dependent plugins WPGraphQL, WP Gatsby installation and exposing WordPress data endpoint to Gatsby site by updating gatsby-config.js were discussed.

The objective of this part 2 of the three-parts series is to expand the Gatsby site by update its global components, namely Layout, refactoring Header and adding Footer components. We will also install and configure Gatsby plugin Sass and add basic global layout with CSS Module.

Learning series
Part 1: Site Set Up and Installation
Part 2: Working with Global Layout and Site Header and Basic Styling (this post)
Part 3: Working with Posts and Pages

Part 2: Extending the Starter With Sass Plugin

As the name suggests, the starter is a skeleton only project with limitations and known issues. Nevertheless, it has the basic elements of a WordPress powered gatsby site and designed to be modified and extended functionality as desired.

As outlined in the objectives, in this guide our focus will be to extending its styling options with Sass and CSS module and refactoring its global components like Header, Layout and add a missing Footer component.

Working with Global Components

For the site styling, the starter uses chakra UI and very basic styling. In this section, we will extend its styling of pages, posts, images styling using Gatsby plugin Sass and CSS module. First, lets install the Sass plugin and add to the configuration.js file.

Step 1: Install Sass Plugin

Just like styling gatsby sites with external style.css, the gatsby-plugin-sass provide support of SASS/SCSS style sheets too.

#! install node-sass & gatsby-sass
yarn add node-sass gatsby-plugin-sass
#! or with npm
npm install --save node-sass gatsby-plugin-sass

Take a note that while installing the gatsby-plugin-sass, its required dependencies node-sass should also be installed.

Step 2: Add the plugin & configure gatsby-config.js file

Lets add the gatsby-plugin-sass plugin in the gatsby-config.js file as shown below.

// include in gatsby-config.js
 module.exports = {
  siteMetadata: {
   // ..
  },
  // ..
  },
  {
    plugins [
    {
     // ...
    },
    // options can be included
    `gatsby-plugin-sass`
    // include options
   ],
}
Step 3: Create styles in .scss files and use by import or require methods
// using import to component
import("./src/styles/global.scss")

//require in gatsby-browser.js file
require('./src/styles/global.scss')

In the example above, the global.scss is imported to a component file or it can also be added in gatsby-browser.js with require statement.

Step 4: Sass Structure

The SCSS files can be structured in several different ways. In this project, we elected to use under a /src/styles sub-directory as shown below:

#! style directory (partial)
├── src
│   └── styles
│       └── base
│           └── resets.css
│           └── variables.css
│       └── scss
│           └── elements.css
│           └── footer.module.css
│           └── header.module.css
│           └── mainNav.module.css
│           └── site.module.css
│           └── ...
│       └── main.scss

Because this project is not being about Sass setting up variables and using Sass syntax are not discussed in this post. They could be found in this Sass guide.

Additional Information: SASS Basics | Learn Sass

Step 5: Adding Common Styles to Layout Component with CSS Module

To add a css module into a component, lets create a file named src/styles/scss/site.module.scss and paste the following CSS rules:

/* src/styles/scss/site.module.css  */
.site_main {
   background-color: whiteSmoke;
}
.site_content {
   padding: 3rem 1rem 1rem;
     img {
       display: block;
       width: 100vw;
     }
}
@media screen and (min-width: 600px) {
   .site_content {
       padding: 1em;
       width: 780px;
       margin: 0 auto;
       font-size: 1.125rem;
         img {
           display: block;
           width: inherit;
	}
   }
}

I will also make use a simple <Layout /> component that was created previously and being used in most of my other projects. To style components with CSS module, style a component using CSS Modules described in Gatsby Doc was followed.

// src/components/layout.js
import React from "react"
import Header from "./header"
import Footer from "./footer"
import styles from "../styles/scss/site.module.css"
import "../styles/main.css"

const Layout = ({ children }) => (
  <section>
    <Header />
      <div className={styles.site_main}>
        <div className={styles.site_content}>
          {children}
        </div>
      </div>
    <Footer />
  </section>
)

export default Layout

In the layout.js components, the chakra-UI styling elements were removed and replaced with common HTML markup as shown above. The site.module.css rules were imported to the <Layout /> component by giving variable name styles (line 5) and the variable name is referenced to style site_main and site_content elements (lines: 11-12).

Refactoring Header Component

The default header.js component is very basic with Gatsby logo (line 12) and a title (line 12). In the starter, the menu.js component is not part of the header.js component but layout.js component.

// header.js from the starter
import React from "react"
import { Heading, Box, Grid } from "@chakra-ui/core"
import { Link } from "gatsby"
import GatsbyLogo from "../assets/svg/gatsby.inline.svg"

export default () => (
  <Heading as="h1">
    <Link to="/">
      <Grid gridTemplateColumns="50px 1fr" gridGap="20px">
        <Box maxW={50}>
          <GatsbyLogo />
        </Box>
        <span
          style={{
            transform: `translateY(5px)`,
            display: `inline-block`,
          }}
        >
          Gatsby Source WordPress V4 demo
        </span>
      </Grid>
    </Link>
  </Heading>
)

In this guide project, we will refactor the header.js component to include site title and description from the WordPress endpoint settings and also include menu.js (the top navigation) component in header component.

// refactored header component
import React from "react"
import { graphql, Link, useStaticQuery } from "gatsby"
import Menu from "./menu"
import style from "../styles/scss/header.module.css"
import logo from '../images/gatsby-icon.png'

const Header = ( ) => {
  const { wp } = useStaticQuery(graphql`
    {
      wp {
        generalSettings {
          title
          description
        }
      }
    }
  `)
  return (
    <header className={style.header_wrapper}>
      <div className={style.brand}>
       
        <Link to="/">
         <img src={logo} alt="logo" width="100" height="100" display="inline-block" 
              marginBottom= "0"  className={style.site_logo} />
          </Link>
          <div className={style.site_header} >
            <div className={style.site_title}>
              <Link
                to="/"
                dangerouslySetInnerHTML={{ __html: wp.generalSettings.title }} /> 
             </div>
             <div className={style.site_description}
                dangerouslySetInnerHTML={{
                __html: wp.generalSettings.description }} />
           </div>
        </div>
           <Menu />    
    </header>
  )
}

export default Header

For styling Header.js components, I borrowed the following CSS rules described by Morten Rand-Henriksen in his recent LinkedIn Learning Gatsby course applied using CSS module, as described in the previous section.

/* src/styles/scss/header.module.css */
.header_wrapper {
  padding: 1rem;
  font-size: 84%;
  font-family: var(--highlight-font);
  text-align: center;
  background-color: white;
}
.site_logo {
  margin: 1rem auto;
  max-width: 6rem;
}
.brand {
  color: var(--rich-black);
}
.brand a {
  color: inherit;
  text-decoration: none;
}
.site_description {
  margin-bottom: 0;
  font-size: 80%;
  font-weight: normal;
  font-style: italic;
}
.site_header {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.site_title {
  font-size: 120%;
  font-weight: bold;
}

@media screen and (min-width: 40rem) {
  .header_wrapper {
    display: flex;
    padding: 1rem 2rem;
    text-align: left;
  }
  .brand a {
    display: grid;
    gap: 0 1rem;
    align-items: center;
    text-align: none;    
  }
  .site_header {
    display: flex;
    flex-direction: column;
    justify-content: center; 
    align-items: flex-start;
  }
  .site_logo {
    grid-row: span 2;
    margin: inherit;
    margin-right: 15px;
  }
  .brand,
  .navigation {
    display: flex;
    flex: 1 1 50%;
  }
  .navigation {
    align-self: center;
  }
}
Refactoring Menu.js Component

The menu.js component used in the header.js component requires some refactoring too, mostly for styling purposes. Lets refactor the menu.js by replacing chakra-ui rules with HTML markup and CSS modules, as shown below.

// src/components/menu.js
import React from "react"
import { Link, useStaticQuery, graphql } from "gatsby"
import style from "../styles/scss/mainNav.module.css"
import { normalizePath } from "../utils/get-url-path"

const Menu = () => {
  const { wpMenu } = useStaticQuery(graphql`
    {
      wpMenu(slug: { eq: "main-menu" }) {
        name
        menuItems {
          nodes {
            label
            url
            parentId
            connectedNode {
              node {
                ... on WpContentNode {
                  uri
                }
              }
            }
          }
        }
      }
    }
  `)

  if (!!wpMenu && !!wpMenu.menuItems && !!wpMenu.menuItems.nodes === 0) return null

  return (
      <nav className={style.navigation} >
        <ul>
          {wpMenu.menuItems.nodes.map((menuItem, i) => {
            if (menuItem.parentId) {
              return null
            }

            const path = menuItem?.connectedNode?.node?.uri ?? menuItem.url

            return (
              <li>
                <Link key={i + menuItem.url}
                  to={normalizePath(path)} 
                  >
                    {menuItem.label}
                </Link>
              </li>
            )
          })}
        </ul>
      </nav>
   
  ) 
}
export default Menu

Now lets add CSS rules for the navigation from Morten’s Learn Gatsby tutorial.

/* src/styles/scss/mainNav.module.css */
.navigation ul {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  margin: 1rem;
  padding: 0;
}
.navigation li {
  margin: 0 0.5rem;
  list-style-type: none;
  font-size: 1.1rem;
}
.navigation a {
  display: block;
  line-height: 2;
  text-decoration: none;
  color: #414141;
  font-size: 1rem;
}
.navigation li a:focus,
.navigation li a:hover {
  border-bottom: 2px solid #414141;
}

@media screen and (max-width: 40rem) {
  .navigation::before,
  .navigation::after {
    display: block;
    width: 1rem;
    margin: 1rem auto;
    content: "";
    border-bottom: 1px solid currentColor;
  }
}

@media screen and (min-width: 40rem) {
  .navigation {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    font-size: 1rem;
  }
  .navigation ul {
    margin: 0;
    justify-content: flex-end;
  }
  .navigation li {
    margin-right: 0;
    margin-left: 2rem;
    font-size: 1.25rem;
  }
}

Let’s view the fully styled, responsive header with navigation in a browser.

View in a Browser

After starting over the development server, view the newly created header & navigation menu at http://localhost:8000, the following header with top navigation with header logo, site title, site description should be displayed (as shown below).

Screenshot showing refactored Header component.
Adding Footer Component

Let’s add a simple footer.js component inside /src/components/ folder as shown below:

// src/components/footer.js
import React from "react"
import style from "../styles/scss/footer.module.css"

export default () => (
  <footer className={style.footer}>
     <p>  © {new Date().getFullYear()} | This site is Powered by {'   ' }
       <a href="https://www.gatsbyjs.org"> GatsbyJS</a>  {'   and  '}  
       <a href="https://www.wordpress.org">WordPress</a>
   </p>
  </footer>
)

Please a note that for styling, a simple css module styling rule is imported (line 3) and applied (line 6) as described in the previous section. When viewed in a browser, the following footer should be displayed.

Screenshot showing footer.
Wrapping Up

In this Part 2 tutorial, the starter plugin was extended by refactoring its header, adding footer and applying global styling rules using Gatsby plugin Sass. In the next part, we will refactor and style posts and pages of the starter.

Credits: This post was inspired by the Morten Rand-Henriksen’s recent LinkedIn course Learning Gatsby and styling code snippets are used from its exercise file.

NEXT: Working with Posts and Pages

Useful Resources

While preparing this post, I have referred the following references extensively. Please refer to original posts for more detailed information.