Syntax Highlighting in Gatsby MDX

2 min read

Syntax Highlighting in Gatsby MDX

In this post, we will be looking into how to enable syntax highlighting for Gatsby MDX files using prism-react-renderer

first, we need to install a couple of modules

npm i prism-react-renderer @mdx-js/react

Then, we create the component which we will use in the <MDXProvider/> that is going to provide a wrapper replacement for our application.

gatsby-browser.js

1
const component = {
2
pre: (props) => {
3
const className = props.children.props.className || "";
4
const matches = className.match(/language-(?<lang>.*)/);
5
return (
6
<Highlight
7
{...defaultProps}
8
code={props.children.props.children}
9
language={
10
matches && matches.groups && matches.groups.lang
11
? matches.groups.lang
12
: ""
13
}
14
>
15
{({ className, style, tokens, getLineProps, getTokenProps }) => (
16
<pre className={className} style={style}>
17
{tokens.map((line, i) => (
18
<div {...getLineProps({ line, key: i })}>
19
{line.map((token, key) => (
20
<span {...getTokenProps({ token, key })} />
21
))}
22
</div>
23
))}
24
</pre>
25
)}
26
</Highlight>
27
);
28
},
29
};

To render the code block we added in MDX file to show up on the page we will access props of the child component of <pre/> component as markdown code blocks get compiled into a <pre/> component wrapping the code component. We can dive a level deeper to get the code by using props.children.props.children, as you can see from the screenshot below.

code-block

To get the language attribute of the code block rather than hardcoding the value we look into MDX code block as it comes through as a class name that will look like language-className (for example language-javascript).

```javascript

const text = 'World'

console.log(`Hello ${text}`)

```

To get the language defined in the code component in the MDX file, we will drill down at props.children.props.className, if there is no class name then we might have not put a language on our code block in which case we will default to empty strings. Then we use a name capture group in regex with the name lang to get the language of the language-className. if there are matches

const matches = className.match(/language-(?<lang>.*)/);

gatsby-browser.js

1
import React from "react";
2
import { MDXProvider } from "@mdx-js/react";
3
import Highlight, { defaultProps } from "prism-react-renderer";
4
5
/* eslint-disable */
6
const component = {
7
pre: (props) => {
8
const className = props.children.props.className || "";
9
const matches = className.match(/language-(?<lang>.*)/);
10
return (
11
<Highlight
12
{...defaultProps}
13
code={props.children.props.children}
14
language={
15
matches && matches.groups && matches.groups.lang
16
? matches.groups.lang
17
: ""
18
}
19
>
20
{({ className, style, tokens, getLineProps, getTokenProps }) => (
21
<pre className={className} style={style}>
22
{tokens.map((line, i) => (
23
<div {...getLineProps({ line, key: i })}>
24
{line.map((token, key) => (
25
<span {...getTokenProps({ token, key })} />
26
))}
27
</div>
28
))}
29
</pre>
30
)}
31
</Highlight>
32
);
33
},
34
};
35
36
export const wrapRootElement = ({ element }) => {
37
return <MDXProvider components={component}>{element}</MDXProvider>;
38
};

Following the post and you can find a starter repo here that shows usage of mdx pages and syntax highlighting