Create a Hygraph block renderer with Next.js

In this article, I will show you how you can create your own Hygraph Block renderer to give complete control over your content, create custom blocks for use with next/image etc


Table of contents

Basic principle of a block renderer

All content is made up of blocks. These blocks are things such as Links, Paragraphs, headings and images.

I’ve fetched my data from Hygraph, and I’m running the following statement to show the json output of a post. You will have an array of objects that look like this.

{type: 'heading-two', children: Array(1)}
{type: 'paragraph', children: Array(1)}
{type: 'paragraph', children: Array(1)}
{type: 'heading-two', children: Array(1)}

It’s quite simple to think conceptually about what we want. Where we have a type of heading-two for example, we will want to render a h2 tag on the front end of the website, styled in a certain way.

Let’s look at how we can make that happen!

Create a file and export a default function from it

export default function BlockRenderer({ blocks }) {}

This is actually a React component, which we will pass the full array of blocks to.

Passing all of the blocks to this component

<div className="flex flex-col">
  <BlockRenderer blocks={post.content.json.children} />
</div>

Do stuff with individual blocks

Lets take our Block renderer and do something for a heading-two

export default function BlockRenderer({ blocks }) {
  return (
    <div>
      {blocks &&
        blocks.map((block) => {
          switch (block.type) {
            case "heading-two":
              return (
                <h2
                  id={slugify(block.children[0].text)}
                  key={slugify(block.children[0].text)}
                  className="font-bold mt-4 text-2xl py-4 leading-7 text-slate-900"
                >
                  {block.children[0].text}
                </h2>
              );
            default:
              return <span>{JSON.stringify(block)}</span>;
          }
        })}
    </div>
  );
}

Let’s go through the code here. We are exporting a single react component, which in this case is a div. For a blog, you can make this an article

Within that div, we are mapping over the full array of blocks, and entering into a switch statement. The switch statement is then working dependent on the type of block that is passed into it.

We are then outputting a component for every block, as a child of the outer div, from the map statement. This means everything we return needs a unique key.

You can see we needed to pass an id within the h2 tag so that we can use #these-links within our page for navigation in the article

Adding additional blocks/types within the case statement

export default function BlockRenderer({ blocks }) {
  return (
    <div>
      {blocks &&
        blocks.map((block) => {
          switch (block.type) {
            case "heading-two":
              return (
                <h2
                  id={slugify(block.children[0].text)}
                  key={slugify(block.children[0].text)}
                  className="font-bold mt-4 text-2xl py-4 leading-7 text-slate-900"
                >
                  {block.children[0].text}
                </h2>
              );
            case "image":
              return (
                <Image
                  src={block.src}
                  key={slugify(block.src)}
                  width={block.width}
                  alt={block.altText ? block.altText : "Blog post image"}
                  height={block.height}
                  className="w-full object-cover h-auto"
                />
              );
            default:
              return <span>{JSON.stringify(block)}</span>;
          }
        })}
    </div>
  );
}

We are now handling H2 and image blocks to work the way we want to within our blog post. The default case statement will handle everything else right now and spit out the json content, which is not ideal. When I was making all of the content, I made these red so they stood out, until I had all the types that we use within our blog posts!

I'd encourage you to go and make some for yourself! Careful for paragraphs and bulleted-list! You will need some additional logic on these to make them work as they contain arrays of children!

Copyright Adam Richardson © 2024 - All rights reserved
𝕏