This post is the continuation of How to add a blog to your Gatsby site. What we did in the first part works, but it probably won't look the best.
Using MDXProvider
Just rendering the {children}
prop that we receive in our layout file works, but if we want to have total control over how the HTML components are rendered and make it easier to use custom ones, we have to use the MDXProvider
:
import React from "react"
import { MDXProvider } from "@mdx-js/react"
const PostLayout = ({ children, path }) => {
return <div>
<MDXProvider>
{children}
</MDXProvider>
</div>
}
export default PostLayout
Now we have opened the door world of MDX customization:
Customizing how built-in HTML components are rendered, using the components prop
Not sure why would someone want to do this, but you can for example render every h1
as an image or Rick Astley... you get the idea of how powerful this can be:
<MDXProvider components={{ h1: ({ children }) => <img src="rickroll.jpg" />}} >
{children}
</MDXProvider>
In my case, I want to control how the pre
and code
elements get rendered. Display a macOS-like window for the pre
element (when using triple backticks), and make it a bit more distinguishable from the standard text when using the code
tag (when using single backticks).
Adding syntax highlighting to code examples
For this, we need to customize how the pre
tags render. We'll use prism-react-renderer
that does an excellent job at it.
yarn add prism-react-renderer
or
npm i prism-react-renderer --save
And then define ourCodeWindow
component:
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
function CodeWindow({ children }) {
const { props: { children: source } } = children
return <div>
<Highlight {...defaultProps} code={source} language="javascript">
{({ 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 >
</div>
}
You can read more about how the code inside the Highlight
component works here: https://mdxjs.com/guides/syntax-highlighting
depending on the structure of your components, the source code is in a children
prop of the children
prop that is passed to our CodeWindow
component (childrenception)
// source is the actual string inside the triple backticks
const { props: { children: source } } = children
We can now set this to the components
prop of our MDXProvider
const components = {
pre: props => <CodeWindow {...props} />,
}
const PostLayout = ({ children }) => {
return <div>
<MDXProvider components={components}>
{children}
</MDXProvider>
</div>
}
Voila! Syntax highlighting for our mdx documents!
Bonus: Highlighting different languages
Mdx passes the string that's next to the triple backticks as a class of our custom component, language-${name}
:
// source is the actual string inside the triple backticks
const { props: { children: source, className: languageClass } } = children
// to get the actual name
const language = classLanguage.replace(/language-/, '')
Then you can pass the language to the Highlight
component:
<Highlight {...defaultProps} code={source} language="javascript">
Top comments (0)