How to render pretty code blocks using Contentful Rich Text Editor and Gatsby
Tags: javascript, cms, gatsby
Published: 2022-09-28 21:14:38


[In a previous post we learned how to render YouTube videos using the Rich Text Editor from Contentful](https://miguelcrespo.co/rendering-youtube-videos-using-rich-text-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:

-   How to connect your Gatsby page to Contentful using the [gatsby-source-contentful](https://www.gatsbyjs.com/plugins/gatsby-source-contentful/)

-   How to render the basic content from a rich text editor, [here's a tutorial](https://www.contentful.com/developers/docs/javascript/tutorials/rendering-contentful-rich-text-with-javascript/)

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](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting), so we cannot do things like this to manage highlighting:
```markdown
``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:
```markdown
---
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](https://prismjs.com/), 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`

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

-   You can see in the snippet above that the languages we will support in the blog are:   `javascript, css, markup`
    -   To see a list of all the supported languages, [check here](https://prismjs.com/#supported-languages)

-   The plugins we support are `show-language` and `line-numbers`
    -   Again, if you want to see all the supported plugins, [check their doc](https://prismjs.com/#plugins)

### 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

```javascript
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

```javascript
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.

-   If the expression doesn't match, we'll render a basic `code` block

-   Otherwise, we will render the fancy `Prismjs` elements

Final code
----------

```js
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>
      );
    },
  },
});
```

Image
----------

![Final Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zyb79ygnns9f3gv7lae.png)