Adding Navigation to Posts in Gatsby Site

Note:This is part 5 of five-parts adding functionality to Gatsby site series. This learning post is still in active development and updated regularly.

In the previous learning-note posts series, creating posts with markdown, adding images & prismJS syntax highlighter, and typography were described. The next logical step to add functionality to the site is to add Next and Previous navigation links at the bottom of each posts to provide easier navigation experience to users to navigate next post or previous post.

Learning series
Part 1: Adding Syntax highlighter with Prismjs
Part 2: Styling Gatsby Site with Typography & Sass Plugins
Part 3: Learning to Work with Images in Gatsby Sites
Part 4: Adding Tags to Posts in Gatsby Site
Part 5: Adding Navigation to Posts in Gatsby Site (this post)

The goal of this part 5 of five-parts learning-note posts is to document step by step procedure to add Next and Previous navigation link at the bottom of each post as in Gatsby default blog site (shown below).

Figure: Screenshot of single post display from Gatsby starter blog showing only bottom post navigation section.
Starting Point

As a starting point for this post, the working site used in Part 4 of this learning series is used. To start fresh, a new site named ‘hello-plugin‘ needs to be setup with the Gatsby default starter hello-world as described previously. How to add markdown posts to a fresh installed site is described in previously in this post.

Step 1: Updating gasby-node.js file

The first step is to update the gatsby-node.js file with Next & Previous Links as shown below:

// gatsby-node..js
....
 // create posts
  posts.forEach(({ node }, index) => {
     createPage({
        path: node.fields.slug,
        component: blogTemplate,
        context: {
           slug: node.fields.slug,
           prev: index === 0 ? null : posts[index - 1],
           next: index === result.length - 1 ? null : posts[index + 1],
        }, // additional data can be passed via context
     })
  })
...
//

In the example above, inside the forEach in create posts block, prev and next are defined (lines:10-11). First, for the prev link, the index is set to zero and when index is zero. If there is no post to move backward to then we will get posts(index-1) meaning the post before the current post. Likewise, for the next post link, the index is set to result.length-1 (line 10) meaning if this is the last post, then there is no next post, or else we will get posts[index + 1] meaning the post after the current post.

The value passed inside context object can be passed to every posts as props.pageContext.

Step 2: Create a prevnext.js Component

After defining next and previous post (step 1), the next step is to add in post component. Though it can be directly added to the Blog-post.js component (for example, starter blog lines: 52-77), for simplicity a separate nextprev.js component is created in /src/components/ folder to handle the next post and previous post as described in this post.

// src/components/prevnext.js

import React from 'react'
const PrevNext = (props) => {

 const { prev, next } = props
   return (
      <ul className="post-navigation">
        <div className="nav-links">
          {prev && <li className="nav-previous"><a href={prev.fields.slug}>
           ← PREVIOUS :   {" "}
              {prev.frontmatter.title}</a></li>}
          {next && <li className="nav-next"><a href={next.fields.slug}>
              NEXT :   {" "} {next.frontmatter.title} →
          </a></li>}
        </div>
     </ul>
    )
}

export default PrevNext;

In the code above, PrevNext component is defined as const (line 4) and prev, next as props (line 6). Then the next, prev props are returned as unordered list (lines: 8-17) with prev && and link to {prev.fields.slug} (lines 10-12) followed by next && and {next.fields.slug} (lines: ). The double ampersand checks the truthiness of the value and so if next or prev is true, it will render this link.

Step 3: Update Blog-post.js Template to Display Links

The <PrevNext /> component created in the previous step is imported to the blog-post.js template component and updated it as shown below:

// src/templates/blog-post.js
import React from 'react';
import { graphql } from "gatsby"
import Layout from '../components/layout';
import PrevNext from '../components/prevnext';

function BlogPost(props) {
  const { title } = props.data.markdownRemark.frontmatter;
  const { prev, next } = props.pageContext;
  return (
   <Layout>
    <div>
     <h1 className="single-entry-title">{title}</h1>
     <div dangerouslySetInnerHTML={{ __html: props.data.markdownRemark.html }}/>
         {/* tags code here */}
         {/* add next-prev */}
       <PrevNext prev={prev && prev.node} next={next && next.node} />
    </div>
  </Layout>
  )
}

export default BlogPost;        

// graphql query 
....

In the example above, the <PrevNext /> component created in the previous step 2 is imported to Blog-post.js component (line 5). The prev and next const are defined as props.context variables in line 9. The prev & next variables are passed to <PrevNext /> component (line 18) as prev && prev.node and next && next.node, respectively.

Step 4: Apply Basic Styling

After applying basic styling to the next & prev link, re-start the development server. When viewed in a browser at localhost:8000, the Next & Previous links should appear just underneath the post as shown below:

Figure: Screenshot of single post display showing post navigation at the bottom section of post for easy navigation.
Next Step

Next logical step for a functioning site is to add SEO component, Manifest file, Sitemap, Offline Support which will be covered in a separate Preparing a Site for Deployment post.

Wrapping Up

In the previous posts in this adding functionalities series, how to add syntax highlighter, images, typography & styling were covered. In this learning-note posts, basic steps to display Next and Previous navigational link to display at the bottom of markdown post were discussed.

Useful Resources

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