How to Integrate Prism.js with Next.js 13

How to Integrate Prism.js with Next.js 13

Arif sardar

Published on 2nd Jun, 2023

3 min read

Prism.js
Next.js 13

Prism.js is an open-source JavaScript library that provides developers with a simple yet feature-rich solution for syntax highlighting. Developed by Lea Verou, Prism.js stands out for its lightweight footprint and robust functionality. It allows developers to beautifully highlight code snippets across a wide range of programming languages and markup formats, creating visually stunning and easily readable content.

Yet prism.js is an excellent library for syntax highlighting, it is very tricky and complex to properly integrate it with frameworks like Next.js. So, in this blog post, I will show you some of the best ways to integrate Prism.js with Next.js 13.

Method 1

You can simply import prism js in a client component, and through useEffect() hook, you can highlight all code blocks at once.

BASH
npm install prismjs

Or,

BASH
yarn add prismjs

Import CSS to app/layout.tsx

You can check out all the different language support and themes you add to your site here at Prism.js. I chose the tomorrow theme.

TSX
import "prismjs/themes/prism-tomorrow.css";

Highlight code through useEffect()

BLOG.TSX
import Prism from "prismjs";
const Blog = ({ post }: { post: string }) => {
  useEffect(() => {
    Prism.highlightAll();
  }, [post]); // <--- run when post updates
 
  return (
  	<>
  		{...}
  	</>
  );
}
Highlight code through useEffect()

Method 2

The method 1 is not the optimized method and contains some issues. Although it will work fine, it may cause a poor user experience. It causes a hydration error in the browser, as the HTML sent from the server and the final rendered HTML don't match.

However, if you are pre-rendering your site, there is a better alternative. Specifically, we are going to be looking at using data coming from a blog, as this is how this site is generated. We can get rid of the useEffect Prism call in the front-end code, and move all the highlighting work to server-side/build time!

Add some necessary dependencies:

BASH
npm install prismjs cheerio html-entities

Or,

BASH
yarn add prismjs cheerio html-entities

Import CSS to app/layout.tsx

You can check out all the different language support and themes you add to your site here at Prism.js. I chose the tomorrow theme.

TSX
import "prismjs/themes/prism-tomorrow.css";

Highlight code in the server

You can use both server components and getServerSideProps() / getStaticProps()

Here I showed a server component.

CONTENT.TSX
import React from "react";
import Prism from "prismjs";
import { load } from "cheerio";
import { decode } from "html-entities";
 
export default function Content({ data }: { data: string }) {
  var newdata = data;
  const $ = load(data);
  const $codes = $("code[class^=language]");
  if ($codes.length > 0)
    $codes.each(function () {
      const $code = $(this);
      const lang = $code.attr("class")?.replace("language-", "") || "";
      const code = decode($code.html());
 
      try {
        // default loaded languages with prisma, skip to decrease build times
        if (!["javascript", "css", "clike", "markup"].includes(lang))
          require("prismjs/components/prism-" + lang);
        $code.html(Prism.highlight(code, Prism.languages[lang], code));
        $code.parent("pre").addClass(`language-${lang}`);
      } catch (e: any) {
        console.error(e);
        console.log("Prismjs error, loading default languages plane text");
        $code.html(Prism.highlight(code, Prism.languages["clike"], code));
        $code.parent("pre").addClass(`language-clike`);
      }
      newdata = $.html();
    });
 
  return (
    <div
      className={`ck-content`}
      dangerouslySetInnerHTML={{ __html: newdata }}
    ></div>
  );
}
Highlight code in the server

As long as we have the prism CSS in our front-end bundle, we don’t have to use any JavaScript on the front end to get beautiful code highlighting. This creates the most performant front-end experience by allowing us to load fewer dependencies and run less JS in the front end!

© 2024 Arif Sardar. Made In India.

Version 4. Powered by Vercel (Next JS).