Add Previous and Next Article Links in Gatsby
Tags: gatsby, react, javascript, blogging
Published: 2019-10-08 14:40:22

---
title: Add Previous and Next Article Links in Gatsby
published: true
description: Learn how to add "previous article" and "next article" links to a Gatsby site.
tags: gatsby, react, javascript, blogging
canonical_url: https://stevenmercatante.com/add-prev-and-next-article-links-in-gatsby
---

___
*This post was originally published at [stevemerc.com](https://stevenmercatante.com/add-prev-and-next-article-links-in-gatsby)*
___

_Yo! You might want to check out this article first on [Managing Draft Articles in Gatsby](https://stevenmercatante.com/manage-draft-posts-in-gatsby/)._

Lots of sites include "Previous Article" and "Next Article" buttons/links on the bottom of their articles. I wanted some, too!

### Updating the UI

Let's start with the fun stuff first - updating the UI. I've got a template that renders the actual markdown content, and I want to add the previous and next buttons to it:

```jsx
// templates/article.js

class ArticleTemplate extends React.Component {
  // These represent the previous and next articles...
  // ... we'll pass these via GraphQL later on
  const { previous, next } = this.props.pageContext

  // Boolean letting us know if we should show prev and next links
  const needsPagination = Boolean(previous) || Boolean(next)

  render() {
    // Imagine the article's body is rendered here...

    {needsPagination && (
      <Pagination>
        {previous && (
          <Link to={previous.fields.slug}>
            <span>← {previous.frontmatter.title}</span>
          </Link>
        )}

        {next && (
          <Link to={next.fields.slug}>
            <span>{next.frontmatter.title} →</span>
          </Link>
        )}
      </Pagination>
    )}
  }
}
```

_(`Pagination` is a styled component - [here's the source](https://gist.github.com/steven-mercatante/b9e1abd2a20ecb9654a901223219cfb5) if you're interested.)_

Refresh your site and you'll see... nothing new! We haven't passed the previous and next articles via GraphQL yet, so `needsPagination` will be `false` and that conditional won't render anything. Let's fix that.

### Updating The Content Pipeline

_Note: I've made some major edits to my `gatsby-node.js`, but the general idea translates to whatever you've got._

_I'm also excluding all the logic that's **not** related to previous and next articles._

```javascript
// gatsby-node.js

function createArticlePages() {
    return new Promise((resolve, reject) => {
      const articleTemplate = path.resolve(`./src/templates/article.js`)

      resolve(
        query.then(result => {
          const articles = result.data.allMdx.edges

          /**
           * We only want to check published articles when
           * fetching the `previous` and `next` ones. So,
           * let's convert the `articles` array into an object
           * whose keys are the article slugs.
           *
           * You don't need this step if you're not setting a
           * `published` flag on articles.
           */
          const publishedArticles = articles
            .filter(article => {
              return article.node.frontmatter.published === true
            })
            .reduce((acc, article) => {
              acc[article.node.fields.slug] = article
              return acc
            }, {})

          articles.forEach((article, index) => {
            const [previous, next] = getPrevAndNextArticles(
              publishedArticles,
              article.node.fields.slug
            )

            createPage({
              path: article.node.fields.slug,
              component: blogArticleTemplate,
              context: {
                slug: article.node.fields.slug,
                previous: previous ? previous.node : null,
                next: next ? next.node : null,
              },
            })
          })
        )
      }
    )
}
```

Most of this is standard Gatsby stuff, but I'm taking an extra step to only fetch the previous and next articles from the subset of published articles (you can skip this step if you don't have a `published` flag for your articles).

If you're wondering why I'm only using `publishedArticles` to fetch the `previous` and `next` articles, and not using it instead of `articles` in the `forEach` below, it's because I want to create article pages regardless of their `published` status - I just don't want to link to unpublished ones.

Near the bottom of the example is where we pass the `previous` and `next` articles via Gatsby's context object, making them available to our `Article` template.

Let's take a look at the `getPrevAndNextArticles` function:

```javascript
function getPrevAndNextArticles(articles, slug) {
  const currentArticleIndex = Object.keys(articles).findIndex(
    slug => slug === slug
  )
  const articlesArray = Object.values(articles)
  let prevArticle
  let nextArticle

  if (currentArticleIndex < articlesArray.length - 1) {
    prevArticle = articlesArray[currentArticleIndex + 1]
  }

  if (currentArticleIndex > 0) {
    nextArticle = articlesArray[currentArticleIndex - 1]
  }

  return [prevArticle, nextArticle]
}
```

This function takes an object of `articles` (where each key is the article's slug) and the `slug` of the article we're currently iterating over in the `forEach` loop of `createArticlePages`. We need to find the index of the current article in relation to its siblings, and then we can return the previous and next articles. If the current article is either the first or the last one in the collection, `previous` or `next` will be null, respectively.

Now when you refresh your site, you should see previous and next article links (assuming you have enough published articles!)

👋 **Enjoyed this post?**

Join my [newsletter](https://stevemerc.com/newsletter/?r=dev) and follow me on Twitter [@mercatante](https://twitter.com/mercatante) for more content like this.