Gatsby is great and the plugin system is very widely developed, however sometimes it can be a bit tricky to get different libraries to work together. In this post we are going to look at the steps to integrate PrismJS syntax highlighting with MDX pages generated with the gatsby-plugin-mdx plugin. This is what we are going to enable:
```javascriptfunction myFunction() {const iterable = [10, 20, 30];for (const value of iterable) {console.log(value);}}``
And this will be the result
function myFunction() {const iterable = [10, 20, 30];for (const value of iterable) {console.log(value);}}
Step 1: Add some code to your MDX
Before we add syntax highlighting let's add the javascript snippet to our MDX markup, run a gatsby build
and inspect the generated HTML in your browser. You should see something like this:
The gatsby-plugin-mdx plugin will wrap your code in a <code\> element, and then place this inside a <pre\> (for preformatted text). Also notice that gatsby-mdx will append the class name <code class="language-javascript">
. This is all PrismJS needs to get to work to identify your code as Javascript (or any of the other languages that are supported out the box)
Step 2: Create a Highlight Wrapper
In order to add formatting to the <code></code>
block above, we can use prism-react-renderer which nicely wraps PrismJS into a React element.
npm install prism-react-renderer
Following the docs for prism-react-renderer we can create a component in our Gatsby site to wrap the code block.
Add a new file ./src/components/CodeBlock.jsx
with the following contents:
import React from 'react'import Highlight, {defaultProps} from 'prism-react-renderer'import theme from 'prism-react-renderer/themes/github'import Prism from "prism-react-renderer/prism";export default (props) => {const className = props.children.props.className || ''const matches = className.match(/language-(?<lang>.*)/)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})}>{line.map((token, key) => (<span key={key} {...getTokenProps({token, key})} />))}</div>))}</pre>)}</Highlight>)}
This is a react component that wraps our content (from props.children
) with the <Highlight />
element imported from prism-react-renderer.
Step 3: Supply Wrapper Component To MDXRenderer
The final step is to tell gatsby-plugin-mdx to use our new wrapper component whenever it wants to render a <pre>
element.
If you are not already, wrap your MDX in a <MDXRenderer />
component as described in the docs for gatsby-plugin-mdx/#mdxrenderer. Then we can add our new CodeBlock
wrapper into the components
object supplied to the <MDXProvider />
import { MDXProvider } from "@mdx-js/react"import CodeBlock from './path/to/CodeBlock'; // The wrapper you created in step 2const components = {pre: CodeBlock}const MdxBlock: React.FunctionComponent<Props> = (props) => {return <MDXProvider components={components}><MDXRenderer>{props.mdx.body}</MDXRenderer></MDXProvider>}export default MdxBlock;
And there you have it. Build and run your gatsby site with gatsby develop
and open the page created from your .mdx
file to see all the glories of code highlighting!