Note: This post is part of Learning Gatsby series. This learning post is still in active development and updated regularly.
In components based websites like ReactJs, GatsbyJs, Vue and others reusable components play an important part. Components like <Header />
, <Footer />
, <Layout />
and others are often shared throughout the site. In most Gatsbyjs site, a simple <Header />
components, as described in this and other posts, works just fine. The same component can be used repeatedly in other sites, as I have done in my projects.
However, in decoupled Gatsby WordPress sites, we may need to add other features, like dynamic navigation which was missing in my previous <Header />
component. Also missing was the logo image along with the site title and site description, as is mostly done in the WordPress setting.
Goals
- Apply useStaticQuery hook to query
siteMetadata
withGraphQL
at build time - Refactor header component to include logo image, site title and site description
- Learn to create dynamic navigation in
<Header />
component
Starting Point
To start fresh, a new site named ‘new-header‘ was setup with the Gatsby default starter hello-world as described previously.
As a starting point, the site setup described in the An Overview of Gatsby Plugins & GraphQL post was used. Using the site’s setup the Header and Layout components were refactored using Gatsby’s useStaticQuery
hook as described in previous note-post.
Step 1: Add a Layout Component
For this project I am using a simple <Layout />
component that was created previously and being used in most of my other projects.
//src/components/layout.js
import React from "react"
import PropTypes from "prop-types"
import "../styles/main.css"
import Header from "./header"
import Footer from "./footer"
import "./layout.css"
const Layout = ({ children }) => {
return (
<>
<Header />
<div siteName="site-main">
<div className="site-content">
{children}</div>
<Footer />
</div>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
Step 2: Create SiteMetadata Hook
How to create useStaticQuery
hook is described in detail in a previous post. A siteMetadata.js
file was created in /src/components/
folder as described previously.
// src/components/siteMetadata.js
import { graphql, useStaticQuery } from "gatsby"
const useSiteMetadata = () => {
const data = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
}
}
}
`
)
return data.site.siteMetadata
}
export default useSiteMetadata
Step 3: Create a Header Component
How to create a simple <Header />
component is described in a previous post. In this project, the <Header />
components was refactored to include logo image along with the site title and site description from the site meta data (file: gatsby-config.js
) from step 2.
// src/components/header.js
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import useSiteMetadata from '../components/siteMetadata';
import logo from '../images/tin.png'
import "../styles/header.css"
const Header = () => {
const { title, description } = useSiteMetadata();
return (
<section className="header">
<div className="header-wrap">
<Link to="/">
<img src={logo} alt="logo" width="175" heigh="175" className="site_logo"/>
<div className="brand">
<div className="site_title"> {title} </div>
<div className="site_description">{description} </div>
</div>
</Link>
</div>
{/* Menu goes here */}
</section>
)
}
Header.propTypes = {
siteTitle: PropTypes.string,
description: PropTypes.string,
}
Header.defaultProps = {
siteTitle: ``,
description: ``,
}
export default Header
Step 4: Add Menu Links items in gatsby-config.js File
How to create dynamic navigation in Gatsby site is described in this Gatsby documentation. First, menu link objects were added (lines: 7-16) inside the siteMetadata
object as described in the document. The menu link object contain two properties, name
(name of menu item) & link
(links to the page navigated to after click).
// gatsby-config.js
module.exports = {
siteMetadata: {
title: `TINJURE`,
description: `Exploring Gatsby & WordPress`,
author: `tinjureWP`,
menuLinks:[
{
name:'Home',
link:'/'
},
{
name:'About',
link:'/about'
}
]
},
plugins: [
//
...
]
}
Step 5: Add the Menu link items to siteMetadata.js
Next the siteMetadata.js
file needs to be updated with the menuLinks
object to include in the graphql
query to extract the menu links.
// src/components/siteMetadata.js
import { graphql, useStaticQuery } from "gatsby"
const useSiteMetadata = () => {
const data = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
menuLinks {
name
link
}
}
}
}
`
)
return data.site.siteMetadata
}
export default useSiteMetadata
Step 6: Menu Component
Lets create simple <Menu />
component at /src/components/menu.js
and pass the menuLinks
objects created in previous step (step 5). First, pass the menuLinks
as props in Menu component (line 6) and then map over as a unordered list (lines 9-15).
// src/components/menu.js
import React from "react"
import { Link } from "gatsby"
import "../styles/navigation.css"
const Menu = ({ menuLinks }) => {
return (
<nav className="navigation">
<ul>
{menuLinks.map(props => (
<li key={props.name}>
<Link to={props.link}>{props.name}</Link>
</li>
))}
</ul>
</nav>
)
}
export default Menu
Step 7: Update <Header />
component to include <Menu />
component
To display the menu navigation in the header, import the <Menu />
component (line 8) and call after the <div> in line 26.
// src/components/header.js
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import useSiteMetadata from '../components/siteMetadata';
import logo from '../images/tin.png'
import "../styles/header.css"
import Menu from "./menu"
const Header = () => {
const { title, description, menuLinks } = useSiteMetadata();
return (
<section className="header">
<div className="header-wrap">
<Link to="/">
<img src={logo} alt="logo" width="175" heigh="175" className="site_logo"/>
<div className="brand">
<div className="site_title"> {title} </div>
<div className="site_description">{description} </div>
</div>
</Link>
</div>
{/* Menu here */}
<Menu menuLinks={menuLinks}/>
</section>
)
}
Header.propTypes = {
siteTitle: PropTypes.string,
description: PropTypes.string,
}
Header.defaultProps = {
siteTitle: ``,
description: ``,
}
export default Header
Step 8: Styling Header & Navigation
For the styling the header and menu in this project, I borrowed the following css rules from Morten Rand-Hendrik’s recent LinkedIn course Gatsby Learning.
/* src/styles/header.css */
.header {
padding: 1rem;
font-size: 84%;
font-family: inherit;
text-align: center;
background-color: #f7f7f7;
}
.site_logo {
margin: 1rem auto;
max-width: 6rem;
}
.header-wrap {
color: #000;
}
.header-wrap a {
color: inherit;
text-decoration: none;
}
.site_title {
margin: 0;
display: inline-block;
font-family: Marta, sans-serif;
font-size: 1.5rem;
font-weight: bold;
color: #404040;
}
.site_title a {
color: #414141;
text-decoration: none;
}
.site_description {
margin-bottom: 0;
color: #414141;
font-size: .9rem;
font-weight: 300;
font-style: italic;
}
.brand {
display: flex;
flex-direction: column;
justify-content: center;
}
@media screen and (min-width: 40rem) {
.header {
display: flex;
padding: 1.25rem 2rem;
text-align: left;
}
.header-wrap a {
display: grid;
grid-template-columns: 7rem auto;
gap: 0 1rem;
align-items: center;
}
.site_title {
font-size: 1.75rem;
}
.site_logo {
grid-row: span 2;
margin: inherit;
}
.brand {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
margin-top: 1.5rem;
margin-left: -1rem;
}
.header-wrap,
.navigation {
flex: 1 1 50%;
}
.navigation {
align-self: center;
}
}
The Navigation CSS rules:
/* src/styles/navigation.css */
.navigation ul {
display: flex;
justify-content: center;
flex-flow: row 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;
position: relative;
}
.navigation li a:focus,
.navigation li a:hover {
color: #000;
border-bottom: 2px solid #000;
}
@media screen and (max-width: 40rem) {
.navigation::before,
.navigation::after {
display: block;
width: 2rem;
margin: 1rem auto;
content: "";
border-bottom: 3px solid #000;
}
}
@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;
}
}
Step 8: View in a browser
After starting over the development server, view the newly created header & navigation menu at http://localhost:8000
, the following dynamically created menu with header logo, site title, site description should be displayed (as shown below).

The header image in smaller screen:

Wrapping Up
In this learning tutorial how create a simple header component with logo, site title, site description with a dynamic menu was created using Gatsby’s build-in useStaticQuery
hook. These handy components can be useful while created decoupled Gatsby WordPress sites.
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.
Useful Resources
While preparing this post, I have referred the following references extensively. Please refer to original posts for more detailed information.