Link prev/next articles dynamically on your gatsby blog

Jan 13, 20201mins read

Introduction

Linking your next and previous article doesn't require any packages to be installed, infact it's quite simple to implement.

If you have an up and running blog with articles then you must have used Gatsby's createPages api. This api provides a createPage function that takes an object as it's first argument, gatsby refers to this object as page object. This page object takes following key's.

  • path : a path url where your articles will be available to read from.
  • component : a path to the react component that'll render the content of the article usually referred to as article template.
  • context : an object using which you can pass any key-value that you would want to read from the article template.

We'll be using the context key to implement this functionality.

Let's code

Each article rendered using article template get's a list of props from the createPage function. It contains a prop named pageContext. Any key-value, we define inside the context will be available through this pageContext prop. We'll be passing two keys named: prev and next representing details of previous and next article respectively.

Getting details of next/previous articles

In order to get list of all articles, we use a GraphQL query. Something like -

const result = await graphql(`
query {
// if you're using just markdown, replace allMdx with allMarkdownRemark
allMdx(sort: { order: DESC, fields: [frontmatter___date] }) {
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`)

This essentially returns all the articles, in the query above, the field edges represent list of all the articles and the field node represent each article. Let's assign the edges to a variable.

const articles = result.data.allMdx.edges

Now to get the next and previous article we can just use articles[index-1].node for previous article and articles[index+1].node for next article. And incase if it's the first article, previous would be null and for the last article next would be null.

For previous article

articles.forEach(({ node }, index) => {
createPage({
...
context: {
...
prev: index === 0 ? null : articles[index - 1].node
}
})
})

For next article

articles.forEach(({ node }, index) => {
createPage({
...
context: {
...
next: index === articles.length - 1 ? null : articles[index + 1].node
}
})
})

Now we have access to the details of previous and next articles inside article template to render links for them.

Using the pageContext

In our article template, we can destructure the props to get the pageContext like

const Article = ({ pageContext }) => {}

Let's extract details of prev/next and save them into variables.

For previous article

const prev = pageContext.prev
? {
url: `/blog/${pageContext.prev.fields.slug}`,
title: pageContext.prev.frontmatter.title
}
: null

For next article

const next = pageContext.next
? {
url: `/blog/${pageContext.next.fields.slug}`,
title: pageContext.next.frontmatter.title
}
: null

Now render them on your article using jsx.

<div>
{prev && (
<Link to={prev.url}>
<span>Previous</span>
<h3>{prev.title}</h3>
</Link>
)}
{next && (
<Link to={next.url}>
<span>Next</span>
<h3>{next.title}</h3>
</Link>
)}
</div>

That's pretty much it, with a little CSS flair you can make it look nice😉

For Reference

I've used this same logic on my gatsby blog as well. For reference, take a look at my article template and my gatsby-node.js file and to see it in action, just scroll a little😅