Vince Parulan
a desktop

How to create table of contents from Contentful's Rich Text field

In this tutorial, I'm assuming you're using Gatsby to render your rich text fields. But the overall idea should be the same whether you're using a different framework!

1. Filter the rich text field

The first step is to filter the rich text field to only include the headings that we want. Usually, we only need all the h2's and the h3's to make a table of contents.

// table-of-contents.js import React from 'react' import { BLOCKS, MARKS } from '@contentful/rich-text-types' const TableOfContents = ({ body }) => { // the body is the json object returned by the rich text field const headingTypes = [BLOCKS.HEADING_2, BLOCKS.HEADING_3] const headings = body.json.content.filter(item => headingTypes.includes(item.nodeType)) // we're recreating the document shape of a rich text // and we're only including the headings. const document = { nodeType: 'document', content: headings, } }

In the code above, we are basically recreating the rich text's shape and only including the headings.

2. Style the headings

To show hierarchy, we can add a margin on all the h3's.

// table-of-contents.js import React from 'react' import { BLOCKS, MARKS } from '@contentful/rich-text-types' const TableOfContents = ({ body }) => { // the body is the json object returned by the rich text field const headingTypes = [BLOCKS.HEADING_2, BLOCKS.HEADING_3] const headings = body.json.content.filter(item => headingTypes.includes(item.nodeType)) const document = { nodeType: 'document', content: headings, } const options = { renderNode: { [BLOCKS.HEADING_2]:: (node, children) => { return ( <li>{children}</li> ) }, [BLOCKS.HEADING_3]:: (node, children) => { return ( <li style={{ marginLeft: `16px`, }} >{children}</li> ) }, } } return ( <nav> <h2>Table of contents</h2> <ul> {documentToReactComponents(document, options)} </ul> </nav> ) }

TODO:

Some of the stuff that I'll add to this blog post:

  • How to generate slug from each heading to create page navigation

Let’s work together.

vince@underscorelabs.co

© 2021, Built with Sanity & Gatsby