noise

Link prev/next articles dynamically on your gatsby blog

Jan 13, 2020
  • gatsbyjs
  • pagination
  • blog
  • articles

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.

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 -

1const result = await graphql(`
2 query {
3 // if you're using just markdown, replace allMdx with allMarkdownRemark
4 allMdx(sort: { order: DESC, fields: [frontmatter___date] }) {
5 edges {
6 node {
7 fields {
8 slug
9 }
10 frontmatter {
11 title
12 }
13 }
14 }
15 }
16 }
17`)

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.

1const 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

1articles.forEach(({ node }, index) => {
2 createPage({
3 ...
4 context: {
5 ...
6 prev: index === 0 ? null : articles[index - 1].node
7 }
8 })
9})

For next article

1articles.forEach(({ node }, index) => {
2 createPage({
3 ...
4 context: {
5 ...
6 next: index === articles.length - 1 ? null : articles[index + 1].node
7 }
8 })
9})

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

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

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

For previous article

1const prev = pageContext.prev
2 ? {
3 url: `/blog/${pageContext.prev.fields.slug}`,
4 title: pageContext.prev.frontmatter.title,
5 }
6 : null

For next article

1const next = pageContext.next
2 ? {
3 url: `/blog/${pageContext.next.fields.slug}`,
4 title: pageContext.next.frontmatter.title,
5 }
6 : null

Now render them on your article using jsx.

1<div>
2 {prev && (
3 <Link to={prev.url}>
4 <span>Previous</span>
5 <h3>{prev.title}</h3>
6 </Link>
7 )}
8 {next && (
9 <Link to={next.url}>
10 <span>Next</span>
11 <h3>{next.title}</h3>
12 </Link>
13 )}
14</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😅

Get in touch

Have a project for me, or just want to say Hi🙋🏽‍♂️? Feel free to email me at prvnbist@gmail.com.