[Storyblok, Gatsby] Integrate syntax highlight in Storyblok rich text

arisa_dev

Arisa Fukuzaki

Posted on May 22, 2021

[Storyblok, Gatsby] Integrate syntax highlight in Storyblok rich text

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, with free hands-on Frontend e-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

Add a headless CMS to Gatsby.js in 5 minutes

[Gatsby, TailwindCSS] Integrate dark mode in 10 minutes

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

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.

$ yarn add storyblok-rich-text-react-renderer
Enter fullscreen mode Exit fullscreen mode

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.

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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

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.

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

Storyblok: Storyblok Rich Text Renderer for React, README, 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

We can use below for code_block data content type.

NODE_CODEBLOCK — (children, { class }) => { ... }
Enter fullscreen mode Exit fullscreen mode

Let's take a look at the example first.

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

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

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.

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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.

$ yarn add react-syntax-highlighter
Enter fullscreen mode Exit fullscreen mode

Import SyntaxHighlighter and a style theme.

import SyntaxHighlighter from "react-syntax-highlighter";
import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism';
Enter fullscreen mode Exit fullscreen mode

You can choose your theme styles from their documentation.

React Syntax Highlighter, README

The example from their documentation shows like this.

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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

It'll be like this.

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>
)
Enter fullscreen mode Exit fullscreen mode

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

You'll see the values we want is returned.

Alt Text

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

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

Hope you found something relevant info for your project!

💖 💪 🙅 🚩
arisa_dev
Arisa Fukuzaki

Posted on May 22, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related