The words Under construction in black text on a yellow background with diagonal black stipes surrounding it
I'm in the process of moving my site. It's still a work in progress. Please excuse the mess and broken links.

Add Line Numbers to Prismjs Syntax Highlighting Code Blocks in a Next.js project

TODO: Pull subtitle into page object

### NOTE - This may not be the best way to do this

I'm having problems with line highlighting with errors like:

code_start_default_section code_end_default_section

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.

Debugging Stuff

I'm moving stuff around right now. All this below is helping me figure out where to put stuff

        -- title

Add Line Numbers to Prismjs Syntax Highlighting Code Blocks in a Next.js project

-- p

### NOTE - This may not be the best way to do this

-- p

I'm having problems with line highlighting with errors like:

-- code/

Warning: Prop `className` did not match. Server: "line-numbers language-jsx" Client: "line-numbers"

-- /code

-- p

I'm now looking at this:

-- p

https://github.com/FormidableLabs/prism-react-renderer

-- p

(_An important note I often forget is that addind <code>className="language-jsx"</code> to the `<code>...</code>` block is required to get highlighting to work. Putting that up here on the top as a reminder_)

-- p

None of the posts I found on the <<link|Prism syntax highlighter](https://prismjs.com/) show how to turn on line numbers in a [Next.js|https://nextjs.org/>> project.

-- p

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

-- p

## 1. The Install

-- p

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

-- code/
-- bash

npm install prismjs

-- /code

-- p

## 2. The Full Code Example

-- p

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

-- code/
-- jsx

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

-- /code

-- p

Using that will output a highlighted and numbered code snippet that <<link|looks like this|https://scratchpad.alanwsmith.com/prism-minimal-example-with-line-numbers-and-theme>>.

-- p

## 3. The Details

-- p

Here's how it all works:

-- p

Prism is made available with:

-- code/
-- jsx

import Prism from 'prismjs'

-- /code

-- p

The theme comes from:

-- code/
-- jsx

import 'prismjs/themes/prism-okaidia.css'

-- /code

-- p

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:

-- p

- <<link|prism.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/prism>>
- <<link|prism-coy.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/coy>>
- <<link|prism-dark.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/dark>>
- <<link|prism-funky.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/funky>>
- <<link|prism-okaidia.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/okaidia>>
- <<link|prism-solarizedlight.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/solarizedlight>>
- <<link|prism-tomorrow.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/tomorrow>>
- <<link|prism-twilight.css|https://scratchpad.alanwsmith.com/prism-default-theme-examples/twilight>>

-- p

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

-- p

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

-- p

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:

-- code/
-- jsx

import 'prismjs/components/prism-jsx.js'

-- /code

-- p

This is what lets us call the <code className="language-jsx border border-black">language-jsx</code> class in our <code className="border border-black language-markup">&lt;code&gt;</code> tags.

-- p

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

-- p

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

-- code/
-- jsx

import 'prismjs/plugins/line-numbers/prism-line-numbers.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'

-- /code

-- p

There's a bunch of other plugins available in the project's 'node_modules/prismjs/plugins' like <code className="language-bash">copy-to-clipboard</code>, <code className="language-bash">line-highlight</code>, etc... that are worth looking at too.

-- p

Actually getting Prism to do its thing is done with <code className="language-jsx">Prism.highlightAll()</code> in <code className="language-jsx">useEffect()</code> with these lines:

-- code/
-- jsx

useEffect(() => {
    Prism.highlightAll()
}, [])

-- /code

-- p

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

-- code/
-- jsx

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

-- /code

-- p

One last note. I use <<link|next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) for my site. I make code blocks with code fences (e.g. &grave;&grave;&grave;). There's no way in the markdown to send a signal to turn on the line numbers in the <code className="language-markdown">&lt;pre&gt;</code> tag. I work around that by [replacing the default components|https://github.com/hashicorp/next-mdx-remote#replacing-default-components>> like this:

-- code/
-- jsx

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

-- /code

-- p

That adds the <code className="language-jsx">className="line-numbers"</code> call to all my <code className="language-markdown">&lt;pre&gt;</code> tags.

-- p

## The Review

-- p

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

-- code/
-- jsx

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

-- /code

-- p

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.

-- p

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


-- categories
-- Next.js
-- CSS
-- Prism

-- metadata
-- date: 2022-01-08 16:28:21
-- id: 23qrlwhb
-- status: published
-- type: post
-- SCRUBBED_NEO: false
-- site: aws