In this article, we will go through the steps on how to enable code highlighting with line numbers for Gatsby MDX files with prism-react-renderer.
If you already haven’t integrated MDX into your project (you should because MDX is awesome), here’s the official guide on Gatsby's documentation to add it to your project. However, if you are already using Markdown Remark in your project, consider Migrating to MDX. In this post, we will integrate PrismJS syntax highlighting with MDX using prism-react-renderer. Also, we are going to add line numbers to code blocks. This is what we are aiming for:
Step 1: Install prism-react-renderer Package
To get started, you need to install prism-react-renderer, which wraps PrismJS into a React component.
npm install prism-react-renderer
When you add a fenced code block in your .mdx file, the gatsby-plugin-mdx will wrap your code in a <pre> element and append a class name to it indicating the programming language. prism-react-renderer uses this to identify the language and highlight the code block.
Step 2: Create the CodeBlock Component
Let's create a React component to add code highlighting with line numbers(optional) to our code blocks. First, create a file CodeBlock.jsx in src/components/, then add the following contents.
// CodeBlock.jsx
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import theme from 'prism-react-renderer/themes/vsDark'
export default function CodeBlock(props) {
const className = props.children.props.className || ''
const matches = className.match(/language-(?<lang>.*)/)
const showLineNumbers = props.children.props.lineNumbers
return (
<Highlight
{...defaultProps}
code={props.children.props.children.trim()}
language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ''
}
theme={theme}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style, padding: '20px' }}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{showLineNumbers && <span className='line-number'>{i + 1}</span>}
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
}
This component highlights code blocks. Optionally, you can add line numbers by passing the meta string lineNumbers to the code block in the .mdx file. If you want a different theme, change the theme import to an available theme of your liking.
Step 3: Add the CodeBlock Component to <MDXProvider>
Go to the file where you use the <MDXRenderer> component (in my case src/templates/blog-post.js which renders my blog posts) and wrap it with the <MDXProvider> component. Then add the CodeBlock component to the components object and pass it to the <MDXProvider> component.
// blog-post.js
// ...
import { MDXProvider } from '@mdx-js/react'
import CodeBlock from '/src/components/CodeBlock.jsx'
const components = {
pre: CodeBlock,
}
const BlogPostTemplate = ({ data, location }) => {
const post = data.mdx
//...
return (
//...
<MDXProvider components={components}>
<MDXRenderer>{post.body}</MDXRenderer>
</MDXProvider>
//...
)
}
export default BlogPostTemplate
Step 4: Styling Line Numbers
To render the line numbers correctly, we will add some styling. Create a file style.css in your src folder and add the following CSS styles. If you already have a global CSS file, append the following styles to it.
/* style.css */
.line-number {
text-align: right;
padding-right: 1em;
user-select: none;
opacity: 0.5;
}
Now in your gatsby-browser.js file, import the file we just created.
// gatsby-browser.js
// custom CSS styles
import './src/style.css'
Step 5: Add Code to .mdx Files
To test code highlighting, open up one of your .mdx files and add some code. If you want line numbering, just pass the meta string lineNumbers after the language declaration. Note: The space is important.
```javascript lineNumbers
function add(num1, num2) {
const result = num1 + num2
return result
}
console.log(add(1, 2))
```
And that's it! Save your files, run gatsby develop, and go to the pages created from .mdx files to see your code blocks highlighted and optionally numbered. If something went wrong, let's put on the debugging glasses and get to work.
Debugging Errors
Here're some errors that popped up when I was integrating prism-react-renderer with MDX.
props.children.props.children.trim is not a function
My blog previously used gatsby-remark-prismjs to highlight code blocks, which conflicted with prism-react-renderer. So I uninstalled it and removed it from the plugins array in gatsby-config.js.
npm remove gatsby-remark-prismjs`
// gatsby-config.js
module.exports = {
plugins: [
//...
{
resolve: `gatsby-plugin-mdx`,
options: {
gatsbyRemarkPlugins: [
- `gatsby-remark-prismjs`,
],
},
}
]
}
Code Block Styling Looks Awful
When the first time I added code highlighting, it looked like this:

Ah, Awful! What's going on? This is the same problem as above, I forgot to remove the existing CSS styles used by gatsby-remark-prismjs in gatsby-browser.js. This caused conflicting styles and resulted in the above mess. To fix this, simply remove the CSS import in gatsby-browser.js.
// gatsby-browser.js
- import "prismjs/themes/prism.css"
Conclusion
If you fixed the bugs and everything went right, congrats🎉. Otherwise, check out the official documentation for gatsby-plugin-mdx, MDX, and prism-react-renderer. Happy coding!

Top comments (1)
meta with lineNumbers is not available in the props. Stuck on this.