DEV Community

Alan W. Smith
Alan W. Smith

Posted on • Originally published at alanwsmith.com

Add Line Numbers to Prismjs Code Blocks in a Next.js Project

(The original version of this post is on my site if you'd like to read it there)


None of the posts I found on the Prism syntax highlighter show how to turn on line numbers in a Next.js project.

In the spirit of sharing so others don't have to hack around like I did, here's how to do it:

1. The Install

Assuming you already have your Next.js project setup and ready, install Prism with:

npm install prismjs
Enter fullscreen mode Exit fullscreen mode

2. The Full Code Example

Next up, the code. Here's a fully functional example you can use in a file (e.g. 'pages/prism-example.js'). It includes a theme (okaidia), a language (jsx), and line numbering. (Details further below.)

import { useEffect } from 'react'

import Prism from 'prismjs'

import 'prismjs/themes/prism-okaidia.css'
import 'prismjs/components/prism-jsx.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'

export default function Page() {
  useEffect(() => {
    Prism.highlightAll()
  }, [])

  const codeSample = `<div className="example">
  {Math.random()}
</div>`

  return (
    <main>
      <pre className="line-numbers">
        <code className="language-jsx">{codeSample}</code>
      </pre>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

Using that will output a highlighted and numbered code snippet that looks like this.

3. The Details

Here's how it all works:

Prism is made available with:

import Prism from 'prismjs'
Enter fullscreen mode Exit fullscreen mode

The theme comes from:

import 'prismjs/themes/prism-okaidia.css'
Enter fullscreen mode Exit fullscreen mode

This is one of the default themes Prism ships with. The others are located in the project's 'node_modules/prismjs/themes' directory. They are:

Switch out the import call to point to whichever one you prefer.

There are also ways to make and use custom themes as well. That's left as an exercise for the reader.


Be default, Prism loads syntax highlighting for "markup, css, clike, and javascript". Other languages need to be imported explicitly. In the example, I'm adding JSX with:

import 'prismjs/components/prism-jsx.js'
Enter fullscreen mode Exit fullscreen mode

This is what lets us call the language-jsx class in our <code> tags.

(Look in your project's 'node_modules/prismjs/components' directory for all the available languages.)


Prepping to use the line numbers is done with these two import statements:

import 'prismjs/plugins/line-numbers/prism-line-numbers.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'
Enter fullscreen mode Exit fullscreen mode

There's a bunch of other plugins available in the project's 'node_modules/prismjs/plugins' like copy-to-clipboard, line-highlight, etc... that are worth looking at too.


Actually getting Prism to do its thing is done with Prism.highlightAll() in useEffect() with these lines:

useEffect(() => {
    Prism.highlightAll()
}, [])
Enter fullscreen mode Exit fullscreen mode

The last two parts that turn on the line numbers and set the language go hand in hand. They're done with className="line-numbers" and className="language-jsx" in:

<pre className="line-numbers">
    <code className="language-jsx">{codeSample}</code>
</pre>
Enter fullscreen mode Exit fullscreen mode

One last note. I use next-mdx-remote for my site. I make code blocks with code fences (i.e. three backticks in a row on the before and after the code). There's no way in the markdown to send a signal to turn on the line numbers in the <pre> tag. I work around that by replacing the default components like this:

<MDXRemote
  {...source}
  components={{
    pre: (props) => (
      <pre className="line-numbers">{props.children}</pre>
    ),
  }}
/>
Enter fullscreen mode Exit fullscreen mode

That adds the className="line-numbers" call to all my <pre> tags.

The Review

Now that you've seen the details, here's that code sample one more time.

import { useEffect } from 'react'

import Prism from 'prismjs'

import 'prismjs/themes/prism-okaidia.css'
import 'prismjs/components/prism-jsx.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'

export default function Page() {
  useEffect(() => {
    Prism.highlightAll()
  }, [])

  const codeSample = `<div className="example">
  {Math.random()}
</div>`

  return (
    <main>
      <pre className="line-numbers">
        <code className="language-jsx">{codeSample}</code>
      </pre>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

Prism also offers line highlighting. There isn't a way to use it with default markdown code blocks since the line numbers are dependent on the specific code snippets. Getting those in place (along with some of the other Prism plugins) requires making new, custom components.

But, that's for another time. For now, syntax highlighting with line numbers has me taken care of.


Alan W. Smith runs his site and a podcast. He's also on Twitter and Twitch from time to time playing around with ideas.alanwsmith.com, jacktorrance.blog, Mono Crack, and SurfTech.tv

Top comments (0)