
Mar 5, 2024
•
#next.js
•
3 mins read
In this tutorial I’ll be teaching you how to add that beautiful code highlighting to your Next.js project. We’ll use Prismjs library and handle synthax highlighting on the server side, so the client will receive the highlighted code without flickering and hydration issues, which is a bit trickier. Without further ado, let’s get started.
So, we’re in VSCode. Here’s a starter code with some boilerplate prepared, I’ll include a repo in the description, but you can use your own project If you want.
In real projects, you’d probably receive a code snippet as a string from an API. But for now, I’ll use a code from layout.jsx file for demonstration purposes and store it in a variable. Feel free to choose your favorite peace of code to use it throughout the tutorial.
// App.tsx
const code = `import './globals.css'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
)
}`;
//...Pass the code to your JSX:
<code>{code}</code>We’ve just rendered the code in our layout.

<code> element uses white-space: pre by default. In real world projects, you may receive a string of code with line breaks handled by \n instead. Install the library:
npm i prismjsImport Prism into your component file:
import Prism from "prismjs";Then, we need to choose a theme. You can go to the prism’s test drive page and choose between all the available themes here and see how it looks. For my taste, I choose “Okaidia” theme.
To add the necessary styles for our theme, we need to import it in that way:
import "prismjs/themes/prism-okaidia.css";Then, we need to import prism components for all the other languages we need. By default, Prismic imports a very few languages, including html, css and javascript. To add support for JSX, we need to manually import it:
import "prismjs/components/prism-jsx";Now, It’s time to write a highlight function that will use Prism to perform synthax highlighting. It will receive a code as a string, performs a highlighting and returns an html string. Basically, it just maps through our code string, finds the code elements and wraps them into <span> elements with appropriate CSS classes that colors our code.
const highlight = (code, language = 'markup') => {
const res = Prism.highlight(code, Prism.languages[language], language);
return res;
}
// ...Then, we can perform highlighting inside our JSX. Remember, we’re doing in on the server side, because it’s a React Server Component.
export default function Home() {
const language = "jsx";
const highlightedCode = highlight(code, language);
return (
//...Remember, that we’ve just returned an html string, not an actual HTMLElement or a collection of HTMLElements. In order to pass it properly, we should use dangerouslySetInnerHTML.
Lastly, we need to add proper CSS classes in this way:
<pre className={`language-${language}`}>
<code
className={`language-${language}`}
dangerouslySetInnerHTML={{
__html: highlightedCode,
}}
></code>
</pre>Let’s see how our page looks like:

Looks brilliant! However, there’s a scrollbar appeared and we’ve lost our line breaks even we’ve handled it by the white-space property. Because we’ve hard-coded our code snippet, we need to manually handle line breaks:
We’ve used dangerouslySetInnerHTML here which is known as an unsecure method, because it is vulnerable to XSS attacks. If you’re in a safe environment, you can skip this step. But for an extra security level here, we’ll use a DOMPurify library to sanitize our html string to preventively remove any XSS attacks.
You may have noticed that the library is DOM-only, so it works only on the client side code. But in our Next.js component, we’re working with the server code, i.e. there’s no DOM.
That’s why we need isomorphic-dompurify. The library makes it possible to seamlessly use DOMPurify on server and client in the same way.
import DOMPurify from "isomorphic-dompurify";
// ...
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(highlightedCode),
}}