How to Integrate Prism.js with Next.js 13

Prism is an awesome and easy library to use to get awesome code snippet highlighting in your blog posts. But integrating it with Next.js is a challenging task.

2nd Jun, 2023 by Arif Sardar

Prism.js, Next.js 13,

3 min. read

180 visitors222 views

Share on:

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.

$ npm install prismjs

Or,

$ 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.

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

Highlight code through useEffect()

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

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

$ npm install prismjs cheerio html-entities

Or,

$ 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.

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> ) }

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!