Syntax Highlighting in Gatsby MDX
2 min read
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
1const component = {2pre: (props) => {3const className = props.children.props.className || "";4const matches = className.match(/language-(?<lang>.*)/);5return (6<Highlight7{...defaultProps}8code={props.children.props.children}9language={10matches && matches.groups && matches.groups.lang11? matches.groups.lang12: ""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.
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
1import React from "react";2import { MDXProvider } from "@mdx-js/react";3import Highlight, { defaultProps } from "prism-react-renderer";45/* eslint-disable */6const component = {7pre: (props) => {8const className = props.children.props.className || "";9const matches = className.match(/language-(?<lang>.*)/);10return (11<Highlight12{...defaultProps}13code={props.children.props.children}14language={15matches && matches.groups && matches.groups.lang16? matches.groups.lang17: ""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};3536export const wrapRootElement = ({ element }) => {37return <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