Skip to content

How to render pretty code blocks using Contentful Rich Text Editor and Gatsby

Posted on:September 28, 2022 at 06:00 AM

In a previous post we learned how to render YouTube videos using the Rich Text Editor from Contentful, in this post we will learn how to render pretty code blocks using the Rich Text Editor from Contentful, I will assume that you already know:

With that said, let’s start!

Adding code snippets to your post content

We will use the built-in code option to insert our snippets to the posts, the problem I faced was that Contentful doesn’t allow to specify the language of a snippet like the Github Flavored Markdown, so we cannot do things like this to manage highlighting:

"```javascript

console.log("Hello World")

“```

Instead, what I came up with was to use the first line of the snippet for metadata, like the language of the snippet, in that way the snippet above would be written like:

---

lang:javascript

console.log("Hello World")

Later in the code we will handle this metadata information, for now let’s add it to the content of our post

Adding code highlighting to our blog

I was checking, and the most popular library by far seem to be PrismJS, it’s easy to add to our Gatsby website, and it’s easy to configure

Installation

To install it, you just need to run this

npm install prismjs babel-preset-gatsby babel-plugin-prismjs

Configuring PrismJS

We installed the babel-babel-preset-gatsby package to be able to tell prismjs which theme to use, and exactly which languages and plugins we want to support in our side and therefore not include unused features, for this we need to create a new file called: .babelrc

{
  "presets": [
    "babel-preset-gatsby"
  ],
  "plugins": [
    [
      "prismjs",
      {
        "languages": [
          "javascript",
          "css",
          "markup"
        ],
        "plugins": [
          "show-language",
          "line-numbers"
        ],
        "theme": "tomorrow",
        "css": true
      }
    ]
  ]
}

javascript, css, markup

Finally, enabling PrismJS in our application

The last step is simply to call Prismjs to start coloring all the <code> tags that it finds, I did it by calling the function inside a useEffect in the React Component that is rendering the blog post

useEffect(() => {
  // call the highlightAll() function to style our code blocks
  Prism.highlightAll();
}, []);

Rendering the right HTML tags

In the section of the code where we render the basic content of the Rich Text Editor, we should add a new option to the renderRichText function, this new option is just a property inside the key renderMark (A code block is a mark in the Contentful language), so it would look like this

renderRichText(post.body, {
  renderMark: {
    [MARKS.CODE]: (text) => {
      return (
        <pre>
          <code>{text}</code>
        </pre>
      );
    },
  },
});

In the code above, every time we find a code block inside the Contentful rich text editor content, we will render the text inside a <pre><code> tags, this is how Prismjs is expecting our code to be

Extracting the language from the code snippet

Now we want to extract the language from the first line of the code snippet, we will look o line to avoid weird behaviors later, and we will use the following regular expression ^lang:(\w+) to test the code snippet.

Final code

renderRichText(post.body, {
  renderMark: {
    [MARKS.CODE]: (text) => {
      const regex = /^lang:(\w+)/;
// If the code snippet doesn't have the expected metadata
      if (!regex.test(text)) {
        return <code>{text}</code>;
      }
// Extract the language
      const language = regex.exec(text)[1];

// Remove the first line to avoid including metadata in the rendered version
      return (
        <pre>
          <code className={`language-${language} line-numbers`}>
            {text.split("\n").slice(1).join("\n")}
          </code>
        </pre>
      );
    },
  },
});