[Storyblok, Gatsby] Integrate syntax highlight in Storyblok rich text
Tags: storyblok, gatsby, react
Published: 2021-05-22 00:05:44

Hi there!

I'm Arisa, a DevRel from this June living in Germany🇩🇪 (A big announcement is coming this June😏)

I have a free online programming learning community called [Lilac](https://note.com/frontendlifeinde/m/m9b8feda1d547), with [free hands-on Frontend e-books](https://zenn.dev/arisa_dev/books)👩‍💻

# Who is this article for?

- Anyone who wants to try out integrating syntax highlight in the Storyblok blog project
- Anyone who wants to build a tech blog with Storyblok & Gatsby.js
- Anyone who wants to know the syntax highlight integration in a Headless CMS with Gatsby.js

To help you understand the prep before integrating syntax highlight in rich text from Storyblok, here are some resources to read📖

> [Storyblok: The Complete Guide to Build a Full-Blown Multilanguage Website with Gatsby.js](https://www.storyblok.com/tp/gatsby-multilanguage-website-tutorial)

> [Add a headless CMS to Gatsby.js in 5 minutes](https://www.storyblok.com/tp/add-a-headless-cms-to-gatsby-5-minutes)

> [[Gatsby, TailwindCSS] Integrate dark mode in 10 minutes](https://dev.to/arisa_dev/gatsby-tailwindcss-integrate-dark-mode-in-10-minutes-1p2c)

I highly recommend you to take a look at the blog post I wrote below.

This blog post requires you to have a basic understanding of the fetching rich text from Storyblok.

The blog post below helps you with hands-on source code :)

> [[Storyblok, Gatsby] Programmatically create blog post pages from data](https://dev.to/arisa_dev/storyblok-gatsby-programmatically-create-blog-post-pages-from-data-2pgo)

# Step 1: Fetch node resolvers, `NODE_CODEBLOCK` with `storyblok-rich-text-react-renderer` 

At this point, I expect you that you completed to generate a blog entry page dynamically with using `gatsby-node.js` file.

If you feel I started to talk about unicorns, go grab my blog post I recommended you above🦄

First things first, install `storyblok-rich-text-react-renderer` if you didn't have yet from the blog post I recommende you to take a look at first.

```shell
$ yarn add storyblok-rich-text-react-renderer
```

Import `render` from `storyblok-rich-text-react-renderer` .

If you followed the blog I asked you to take a look at first, it'll look something like this.

```javascript
import { render } from 'storyblok-rich-text-react-renderer'

export default function BlogEntry({ pageContext, location }) {
  let story = pageContext.story
  story = useStoryblok(story, location)

  return (
    <Layout>
      <p>{ story.content.intro }</p>
      <div>
        {/* 👇 render a rich text data */}
        { render(story.content.long_text) }
      </div>
    </Layout>
  )
}
```

Technically, we already can see `code_block` data content type in the browser without configuring the details of `code_block` data content type. 

It's because `long_text` data content contains all rich text from Storyblok draft JSON.

`code_block` is a data content type to stow code blocks from Storyblok's main dashboard content input.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrk9gd1kab928e7uok1i.png)

But it's not with styles if you see the results in the browser.

Looks treated exactly the same style as paragraph data content type.

We want our `code_block` data content type to be highlighted.

# Step 2: Map node resolvers to custom React components

Don't be paranoid, I'll explain what's node resolvers are👍

The node resolvers are the optional second argument of the `render` function from `storyblok-rich-text-react-renderer` .

There're several values assigned from Storyblok.

```javascript
render(document, {
    markResolvers: { ... }, // inline elements
    nodeResolvers: { ... }, // block elements
    blokResolvers: { ... }, // embedded components
    defaultBlokResolver: (name, props) => ( ... ),
    defaultStringResolver: (str) => ( ... ),
});
```

> [Storyblok: Storyblok Rich Text Renderer for React, README, advanced usage](https://github.com/claus/storyblok-rich-text-react-renderer#advanced-usage)

We'll use `nodeResolvers` this time.

`code_block` data content type is a block element.

It's all written in the documentation.

> [Storyblok: Storyblok Rich Text Renderer for React, README, node resolvers](https://github.com/claus/storyblok-rich-text-react-renderer#node-resolvers)

We can use below for `code_block` data content type.

```
NODE_CODEBLOCK — (children, { class }) => { ... }
```

Let's take a look at the example first.

```javascript
import MyImage from 'components/MyImage';
import { render, NODE_IMAGE } from 'storyblok-rich-text-react-renderer';

render(document, {
    nodeResolvers: {
        [NODE_IMAGE]: (children, props) => <MyImage {...props} />
    }
});
```

It's nothing different from the documentation.

Just the node resolver is an image in this case.

The only differences are below.

1. We don't create a separated component for `code_block` to render
2. Use `NODE_CODEBLOCK`

Based on that, we can write something like this.

```javascript
import { render, NODE_CODEBLOCK } from 'storyblok-rich-text-react-renderer'

export default function BlogEntry({ pageContext, location }) {
  let story = pageContext.story
  story = useStoryblok(story, location)

  return (
    <Layout>
      <p>{ story.content.intro }</p>
      <div>
        {/* 👇 render a rich text data & code_block */}
       {
          render(story.content.long_text, {
            nodeResolvers: {
              [NODE_CODEBLOCK]: (children, story) => {
                  return (
                      <pre>
                        <code { ...story }>{ children }</code>
                      </pre>
                  )
                }
              }
            }
          )
        }
      </div>
    </Layout>
  )
}
```

Let me tell you the results already before you get disappointed.

It won't make any change in the browser😅

It's because we already fetched `code_block` when we rendered `long_text` data content.

If so, why we did all those work?

Trust me.

Soon later, you'll know how this way is much easier than if you try out integrating Prism.js or highlighter.js by yourself.

It's less packages to install, no babel config is required and our code is very short.

But how we'll add the syntax highlight?

We'll combine with React Syntax Highlighter.

# Step 3: Apply React Syntax Highlighter

To do that, let's install it first.

```shell
$ yarn add react-syntax-highlighter
```

Import `SyntaxHighlighter` and a style theme.

```javascript
import SyntaxHighlighter from "react-syntax-highlighter";
import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism';
```

You can choose your theme styles from their documentation.

> [React Syntax Highlighter, README](https://github.com/react-syntax-highlighter/react-syntax-highlighter#readme)

The example from their documentation shows like this.

```javascript
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs';

const Component = () => {
  const codeString = '(num) => num + 1';
  return (
    <SyntaxHighlighter language="javascript" style={docco}>
      {codeString}
    </SyntaxHighlighter>
  );
};
```

It means, as long as we wrap our code elements with `SyntaxHighlighter` component, it might work.

It'll be like this.

```javascript
return (
      <div>
        {
          render(story.content.long_text, {
            nodeResolvers: {
              [NODE_CODEBLOCK]: (children, story) => {
                  return (
                      <pre>
                        <code { ...story }>
                          <SyntaxHighlighter language={ story } style={ tomorrow }>
                            { children }
                          </SyntaxHighlighter>
                        </code>
                      </pre>
                  )
                }
              }
            }
          )
        }
      </div>
)
```

I recommend you to debug children and story with `console.log()` .

You'll see the values we want is returned.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jc8ck55cjxid8jz1hixc.png)

Also, the syntax highlight theme is on🔥

In fact, `NODE_CODEBLOCK` returns an opject property name, `class`.

It means, we should be able to see that the class attribute value of `"language-javascript"` must be added into our code snippet HTML elements.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yadbqxt8udvdhem9mqmi.png)

You mihgt face some situations with the value of undefined if you forget to choose a language when you edit your content in a main dashboard.

As long as we choose the language from our main dashboar in Storyblok, this won't happen👍

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kb4mr88f61nsm95iabib.png)

Hope you found something relevant info for your project!