KIRA WRITES

Prism.JS Syntax Highlighting with React not Working? Try 'useEffect'

prism logo + react logo

Last week when I wrote a tutorial on “How to Add Custom Local Fonts to Next.js and Vercel,” I finally got fed up with not having a way to nicely display my code chunks. I was using markdown’s code callout, but since I am not using any fancy CMS (Content Management System) system, the code that was displayed had no syntax highlighting :(

After a bit of research I decided to use Prism.js syntax highlighter. As soon as I thought I had finished implementing everything and previewed my blog in my browser, I realized my syntax highlighting were not working at all until I refreshed the page. Why is that and how do I fix it?

The Problem:

It seems like Prism syntax highlighter was not applying the styling rules the first time we display the webpage.

The Reason:

How Prism works is that it instructs an existing component -- the codeblocks, to obey the CSS rules specified in prism.css. For Prism to work, it looks for the codeblocks, and when it finds the codeblocks, it applies the CSS rules. That means, the codeblock needs to be rendered fully before Prism's syntax highlighting code is called.

The Solution:

To detect when a component is fully rendered, React's built-in lifecycle method componentDidMount() {} is handy. Quoting React's documentation,

"componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here."
That's exactly what we need. Prism's highlighting function requires the codeblock component being mounted. If you are writing React classes, add Prism.highlightAll() under componentDidMount() will do the trick. Here is the code:
class CodeBlock extends React.Component {
 componentDidMount() {
   Prism.highlightAll();
 }

If you are writing functional components, you can use React's shiny Effect Hook, which allows you to perform side effects such as manually changing the DOM in React components. Again, we add Prism.highlightAll(), this time under useEffect(). Here is the code:

import { useEffect } from "react";
export default function Home() {
  useEffect(() => {
    Prism.highlightAll();
  });
}