Use highlight.js to Style Codeblocks in Next.js

by Lucas Minter

← go back to all posts

Intro

I was moving from TailwindCSS to Bootstrap for styling my website. The content was a Markdown file being fetched from Sanity.io. Previously I was using Tailwind’s Typography plugin to style my codeblocks which worked beautifully and was really easy to use out of the box. It took a while to figure out my replacement but I ended up using highlight.js. Here is how I implemented that in my Next.js blog.

Convert Markdown to HTML

Before using highlight.js, I needed to convert my Markdown into HTML. (If you’re already using an HTML file, skip this section). To do this, I used a parser named Marked. Start by installing it in your app.

npm i marked

Import marked, and then pass your Markdown to it and set it to a variable.

import {marked} from 'marked'

const html = marked(post?.body)

Add this to an element’s dangerouslySetInnerHTML prop and the code should be displayed on your web page.

<article dangerouslySetInnerHTML={{__html: html}} />

Apply Syntax Highlighting to Code Blocks

First you need to install highlight.js.

npm i highlight.js

Then import that into your code.

import hljs from 'highlight.js/lib/common';

I’m importing it from highlight.js/lib/common instead of the default highlight.js/lib/core. Importing hljs from common will automatically have all of the popular languages otherwise you’ll have to import each language separately. I’m doing this because I’m fetching my Markdown file from Sanity.io for a blog and I’ll use code blocks with different languages in different posts. While this will increase the build size slightly, it’s the only option when I can’t specify a language to highlight for each block.

To have styling, add the default styling from highlight.js and import it right below the hljs import.

import hljs from 'highlight.js/lib/common';
import 'highlight.js/styles/default.css';

Next I need to have hljs run immediate when the page loads. I do with useEffect from React and I have it set to highlightAll() to get all of my code blocks.

useEffect(() => {
  hljs.highlightAll();      
}, [])

While I now have styling, the default styling isn’t impressive. highlight.js has a long list of example themes you can add to beautify your code. The one I’m using at the time of writing this post is atom-one-dark. To use this, simply replace the default styles import with import 'highlight.js/styles/atom-one-dark.css';.

Conclusion

And there you go! Your code blocks should now be beautifully highlighted. Here is all of the code for this page ignoring everything that’s not apart of this blog post:

import Link from 'next/link'
import { useEffect } from 'react';

import {marked} from 'marked'
import hljs from 'highlight.js/lib/common';
import 'highlight.js/styles/atom-one-dark.css';

export default function Blog({ post }) {
  const html = marked(post?.body)

  useEffect(() => {
    hljs.highlightAll();      
  }, [])

  return (
    <div className='container my-3'>
      <h1 className='text-center'>
        {post.title}
      </h1>
      <h4 className='my-2 text-center'>by {post.author.name}</h4>
      <p className='my-2 text-center'>
        <Link href='/posts'>
          &larr; go back to all posts 
        </Link>
      </p>
      <div className="row d-flex justify-content-center">
        <article className="overflow-hidden col-12 col-md-10" dangerouslySetInnerHTML={{__html: html}} />
      </div>
    </div>
  )
}