Posted on Leave a comment

Using a Highlight.js with GatsbyJS & WordPress

GatsbyJS is awesome because it allows developers to quickly design, develop and deploy projects. Gatsby sites are automatically optimized for speed and allows us to focus on building something great.

Why use a Code Syntax Highlighter?

If your personal website is littered with pre and code tags – you might want to consider using a code syntax highlighter.

Syntax highlighters are abundant, easy to use, improve readability and really up your dev game.

With syntax highlighting

Without syntax highlighting

I think the images speak for themselves.

Highlight.js

Highlight.js homepage has a interactive demo for syntax highlighting

As mentioned above – there are plenty of options out there when it comes to code syntax highlighters.

We are going to choose highlight.js because it is well-known, easy to use and comes with lots of theme styles.

Setup

First, download highlight,js from npm.

$ npm i highlight.js

Next create a helper file at /src/utils/helper.js.

$ touch src/utils/helper.js

Import the library

// /src/utils/helper.js

import hljs from "highlight.js"

Pick a code theme

Highlight.js has lots of themes available – you can find them all by visiting the official repository, the homepage or running ls in the module’s styles folder.

I chose ‘atom-one-dark’.

// /src/utils/helper.js

import hljs from "highlight.js"
import "highlight.js/styles/atom-one-dark.css"

Configuration

Unless you have some built in meta data or class names which signify the language in your code blocks – you will probably want to use the auto-detect feature.

Trouble is, highlight.js has over 180 languages and detection can be tricky.

I overcame this by narrowing the search to just the languages I know I use in these blocks

// /src/utils/helper.js

...

hljs.configure({
  languages: ["php", "javascript", "json", "bash", "scss"],
})

You can see all the possible options by running hljs.listLanguages() in the console.

Building our code highlighter

Finally we are going to create our highlightCode() function which simple finds all code tags nested within a pre tag and “highlight it”.

// /src/utils/helper.js

...

const highlightCode = () => {
  const codes = document.querySelectorAll("pre > code")
  for (let key in codes) {
    if (typeof codes[key] === "object") {
      hljs.highlightBlock(codes[key])
    }
  }
}

Essentially we are looping through the elements, double checking it is an object then replacing the node with a new element created by the highlighter.

Wrapping up

Finally export the helper – the final result should be:

// /src/utils/helper.js

import hljs from "highlight.js"
import "highlight.js/styles/atom-one-dark.css"

hljs.configure({
  languages: ["php", "javascript", "json", "bash", "scss"],
})

const highlightCode = () => {
  const codes = document.querySelectorAll("pre > code")
  for (let key in codes) {
    if (typeof codes[key] === "object") {
      hljs.highlightBlock(codes[key])
    }
  }
}

export default { highlightCode }

Using our helper function

The new helper we wrote is great but how do we use it? See this was the tricky bit for me.

GatsbyJS + WordPress work together by querying your WordPress database for the appropriate data.

A post’s content is passed as a large string of HTML and the only way to use that HTML in react is to use dangerouslySetInnerHTML.

dangerouslySetInnerHTML

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.

https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

As per the offical react documentation this property name is purposefully scary to remind you its dangerous to set the innerHTML unless your careful.

Luckily our content was written in the WordPress CMS and has already been sanitized for our viewing pleasure.

Highlighting the code blocks

Finally we are going to use the helper we created.

I’m going to assume you have a running Gatsby site with a template setup to display your single posts. If not – the GatsbyJS + WordPress documentation is wonderful and got me started quickly.

Your post will look something like this – where we are creating a content div and passing our posts content via the dangerouslySetInnerHTML property.

// /src/templates/blog-post.js

Import React, { useEffect } from 'react'

export default function BlogPost({ data }) {
  const post = data.allWpPost.nodes[0]

return (
    <Layout>
      <div id="single">
        <h1 className="title section-header">{post.title}</h1>
        <div
          id="content"
          dangerouslySetInnerHTML={{
            __html: post.content,
          }}
        />
      </div>
    </Layout>
  )
}

Most important to understand is we are passing the HTML of our post directly to div#content.

UseEffect

UseEffect is a react lifecycle method – essentially a spot/time in the code where we can run our own functions. Because we are forced to use dangerouslySetInnerHTML – we cannot access or modify the post’s content before hand.

We can however use UseEffect to run our code highlighter after the component is loaded into the DOM and the content created.

Add import your helper and run the highlightCode function in the useEffect block.

// /src/templates/blog-post.js

Import React, { useEffect } from 'react'

...

 useEffect(() => {
    helper.highlightCode()
  })

  return (
...

Your code blocks should now look like a text editor – improving the readability and aesthetic of your blog posts.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.