How to Implement Prism.js for Code Highlighting in Next.js: A Step-by-Step Guide
Prism.js is a beautiful and lightweight syntax highlighting library for the modern web. In this article, we will learn how to highlight code syntax on the web using Prism.js and Next.js.
Setting Up a Next.js Project
Prerequisites
Before you get started, make sure you have the following installed on your machine:
Node.js: Latest version of Node.js.
npm (Node Package Manager): This comes with Node.js. Alternatively, you can use yarn as a package manager.
A Next.js application: This article will not cover how to create a Next.js application.
Installing necessary packages
Once your Next.js application is set up, you need to install the necessary packages for Prism.js. Run the following command into install necessary packages:
npm install prismjs
With these steps, your Next.js project is now set up and ready for integrating Prism.js for code highlighting.
Integrating Prism.js with Next.js
To use Prism.js for highlighting your code on the web, the HTML must be fully loaded in the browser before applying the syntax highlighting.
Importing Prism.js in your Next.js project
As we have already installed Prism.js, we need to import it where code highlighting is required:
import prism from "prismjs";
Setting up Prism.js themes
Import the Prism.js library and the desired theme from the prismjs
package:
import prism from "prismjs";
import "prismjs/themes/prism-okaidia.min.css";
Here are all the available themes you can choose from:
prism-coy.css
prism-coy.min.css
prism-dark.css
prism-dark.min.css
prism-funky.css
prism-funky.min.css
prism-okaidia.css
prism-okaidia.min.css
prism-solarizedlight.css
prism-solarizedlight.min.css
prism-tomorrow.css
prism-tomorrow.min.css
prism-twilight.css
prism-twilight.min.css
prism.css
prism.min.css
You can select any of these themes based on your preference.
If you want to implement prism-coy.css
then you can import like this
import prism from "prismjs";
import "prismjs/themes/prism-coy.min.css"; // or import "prismjs/themes/prism-coy.css"
Highlighting Code in Next.js Components
To highlight the code on the web, we need to consider a few things:
The code must be within a
code
tag. Acode
tag inside apre
tag works even better.A className must be provided to the
pre
tag orcode
tag according to the programming language to be highlighted, such aslanguage-typescript
,language-bash
,lang-typescript
, orlang-bash
. You can uselang
orlanguage
as your choice; both will work.The respective language plugin must be imported.
All HTML should be fully loaded before invoking Prism.
Let's highlight a simple statement for typescript.
"use client";
import prism from "prismjs";
import "prismjs/themes/prism-okaidia.min.css"; // theme for code appeareance
import "prismjs/components/prism-typescript"; // this plugin will hightlight typescript code
import { useEffect } from "react";
export default function Page() {
useEffect(() => {
prism.highlightAll();
}, []);
return (
<main>
<section>
<h1 className="text-3xl font-bold text-center mt-8">
Step-by-Step Guide to Using Prism.js for Code Highlighting in
Next.js
</h1>
<div className="max-w-4xl mx-auto mt-8">
<pre className="language-typescript">
<code>console.log("Hello, world!");</code>
</pre>
</div>
</section>
</main>
);
}
The preview of this code highlight is:
How is it working?
First of all, Prism.js and the theme
prism-okaidia.min.css
are imported.The
language-typescript
class is provided to thepre
tag for better highlighting of TypeScript.The TypeScript plugin
prism-typescript
is imported, which is responsible for highlighting typescript code.A
useEffect
hook is used for invoking Prism, which ensures the HTML is fully loaded before highlighting the code.
Loading Different Languages and Plugins
Let's highlight code of C, bash and python code:
"use client";
import prism from "prismjs";
import "prismjs/themes/prism-okaidia.min.css"; // theme
import "prismjs/components/prism-c"; // plugin for C
import "prismjs/components/prism-bash"; // plugin for bash
import "prismjs/components/prism-python"; // plugin for python
import { useEffect } from "react";
export default function Page() {
useEffect(() => {
prism.highlightAll();
}, []);
const pythonCode = `print("Hello, World!")`;
const cCode = `#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}`;
const bashCode = `echo "Hello, World!"`;
return (
<main>
<section>
<h1 className="text-3xl font-bold text-center mt-8">
Step-by-Step Guide to Using Prism.js for Code Highlighting in
Next.js
</h1>
<div className="max-w-4xl mx-auto mt-8">
<p className="font-bold mt-4">C</p>
<pre className="language-c">
<code>{cCode}</code>
</pre>
<p className="font-bold mt-7">Python</p>
<pre className="language-python">
<code>{pythonCode}</code>
</pre>
<p className="font-bold mt-7">Bash</p>
<pre className="language-bash">
<code>{bashCode}</code>
</pre>
</div>
</section>
</main>
);
}
The preview of code highlighting is shown below.
Note: Don't forget to import respective plugin for specific language support and to give respective className for the
pre
tag.
Server-Side Rendering Considerations
Considering server-side rendering, we can create a client component PrismHighlighter
that executes the Prism.js highlighting function. This component can be called in the main page without converting the main page to a client component.
"use client";
import prism from "prismjs";
import "prismjs/themes/prism-okaidia.min.css"; // theme
import "prismjs/components/prism-c"; // plugin for C
import "prismjs/components/prism-bash"; // plugin for bash
import "prismjs/components/prism-python"; // plugin for python
import { useEffect } from "react";
export function PrismHightler() {
useEffect(() => {
prism.highlightAll();
}, []);
return null;
}
This function can now be called in the main page:
import { Suspense } from "react";
import dynamic from "next/dynamic";
const SyntaxHighlighter = dynamic(
() =>
import("@/components/SyntaxHighlighter").then(
(mod) => mod.SyntaxHighlighter
),
{ ssr: false }
);
export default function Page() {
const pythonCode = `print("Hello, World!")`;
const cCode = `#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}`;
const bashCode = `echo "Hello, World!"`;
return (
<main>
<section>
<h1 className="text-3xl font-bold text-center mt-8">
Step-by-Step Guide to Using Prism.js for Code Highlighting in
Next.js
</h1>
<div className="max-w-4xl mx-auto mt-8">
<p className="font-bold mt-4">C</p>
<pre className="language-c">
<code>{cCode}</code>
</pre>
<p className="font-bold mt-7">Python</p>
<pre className="language-python">
<code>{pythonCode}</code>
</pre>
<p className="font-bold mt-7">Bash</p>
<pre className="language-bash">
<code>{bashCode}</code>
</pre>
</div>
</section>
<Suspense>
<PrismHightler />
</Suspense>
</main>
);
}
This approach ensures proper syntax highlighting on the server side while keeping the main page as a server component.
Using useRef Hook
While prism.highlightAll()
attempts to highlight all the code on the page, it can be inefficient as it checks every element to determine if it contains code. This blanket approach can lead to unnecessary processing, especially on pages with a lot of content.
To improve efficiency, we can use the useRef
hook to target and highlight only specific code blocks. By focusing on precise sections, we avoid the overhead of scanning the entire page, making the highlighting process more efficient and streamlined. Let's modify the PrismHandler
code to utilize the useRef
hook for this purpose.
"use client";
import prism from "prismjs";
import "prismjs/themes/prism-okaidia.min.css"; // theme
import "prismjs/components/prism-c"; // plugin for C
import "prismjs/components/prism-bash"; // plugin for bash
import "prismjs/components/prism-python"; // plugin for python
import { ReactNode, useEffect, useRef } from "react";
type Props = {
code: ReactNode;
language: "c" | "python" | "bash";
};
export function PrismHightler({ code, language }: Props) {
const ref = useRef<null | HTMLPreElement>(null);
useEffect(() => {
if (ref.current) prism.highlightElement(ref.current);
}, []);
return (
<pre ref={ref} className={`language-${language}`}>
<code>{code}</code>
</pre>
);
}
In the above code, we use the useRef
hook to reference a specific pre
tag. By leveraging the prism.highlightElement()
function, we can efficiently highlight the code block. This approach ensures that only the targeted code block is processed, avoiding unnecessary overhead and improving performance.
Now we, can call this component in the main page like this
import { Suspense } from "react";
import dynamic from "next/dynamic";
const SyntaxHighlighter = dynamic(
() =>
import("@/components/SyntaxHighlighter").then(
(mod) => mod.SyntaxHighlighter
),
{ ssr: false }
);
export default function Page() {
const pythonCode = `print("Hello, World!")`;
const cCode = `#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}`;
const bashCode = `echo "Hello, World!"`;
return (
<main>
<section>
<h1 className="text-3xl font-bold text-center mt-8">
Step-by-Step Guide to Using Prism.js for Code Highlighting in
Next.js
</h1>
<div className="max-w-4xl mx-auto mt-8">
<p className="font-bold mt-4">C</p>
<PrismHightler language="c" code={cCode} />
<p className="font-bold mt-7">Python</p>
<PrismHightler language="python" code={pythonCode} />
<p className="font-bold mt-7">Bash</p>
<Suspense>
<PrismHightler language="bash" code={bashCode} />
</Suspense>
</div>
</section>
</main>
);
}
This code also results same output as before but with better performance.
Styling and Customization
You can override the default style of your code block using !important
in the CSS.
import { PrismHightler } from "@/components/PrismHightler";
import { Suspense } from "react";
export default function Page() {
const pythonCode = `print("Hello, World!")`;
const cCode = `#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}`;
const bashCode = `echo "Hello, World!"`;
return (
<main>
<section>
<h1 className="text-3xl font-bold text-center mt-8">
Step-by-Step Guide to Using Prism.js for Code Highlighting in
Next.js
</h1>
<div className="max-w-4xl mx-auto mt-8">
<p className="font-bold mt-4">C</p>
<pre className="language-c !bg-gray-900">
<code>{cCode}</code>
</pre>
<p className="font-bold mt-7">Python</p>
<pre className="language-python !bg-slate-950">
<code>{pythonCode}</code>
</pre>
<p className="font-bold mt-7">Bash</p>
<pre className="language-bash">
<code>{bashCode}</code>
</pre>
</div>
</section>
<Suspense>
<PrismHightler />
</Suspense>
</main>
);
}
The preview of the overridden code is:
Common Issues and Troubleshooting
Highlighting might not work due to several factors such as:
Forgot to import theme: Ensure that you have imported the theme from Prism.js.
Mismatch of language plugin: There might be a chance that you imported one language plugin but expected to highlight another language.
Missing className in the
pre
tag: After importing the language plugin, make sure to give a className such aslanguage-typescript
to thepre
tag of the code block.Forgot invoking Prism: You may have forgotten to invoke Prism.js, which executes the highlighting process.
HTML not rendering: Before highlighting the code, ensure that the HTML is fully loaded.
Conclusion
This article provides a step-by-step guide to integrating Prism.js, a lightweight syntax highlighting library, with a Next.js project. It covers setting up a Next.js application, installing and importing Prism.js, using various themes, highlighting code in components, considering server-side rendering, and troubleshooting common issues. Customize your code blocks with themes and additional CSS to enhance your web application's code presentation.
Subscribe to my newsletter
Read articles from Gopal Adhikari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Gopal Adhikari
Gopal Adhikari
I am a web developer with interest in mobile app development and cloud.