Author: David Fekke
Published: 7/3/2021
MDX is a hybrid of Markdown syntax and React JSX syntax. Authors who are writing posts in Markdown can use React components in their posts.
Currently Markdown allows authors to add HTML tags to their posts. One of the nice things about React is that it makes it possible for us to create components of a combination of HTML elements, and then reuse those elements in our React applications. MDX allows us to take those same components and use it in our Markdown posts.
import { Link } from 'gatsby'
import Layout from '../components/layout'
import Image from '../components/image'
import SEO from '../components/seo'
<SEO title="Home" keywords={['gatsby', 'application', 'react']} />
# Hi people
Welcome to your new Gatsby site.
Now go build something great.
<div style={{ maxWidth: '300px', marginBottom: '1.45rem' }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
Adding MDX to your Blog
Currently I use regular Markdown for my blog. I decided I wanted to see what would be involved to add MDX to my blog. In my current implementation of my Gatsby site I am using the gatsby-transformer-remark
plugin for converting markdown into Gatsby data that can be used to render my blog posts.
Gatsby provides an excellent tutorial on how to take an existing Gatsby blog using starter site, and convert it to use MDX instead of markdown.
https://www.gatsbyjs.com/blog/2019-11-21-how-to-convert-an-existing-gatsby-blog-to-use-mdx/
This post is from 2019, and some of the line numbers do not match, but it can still be used for a basis of converting your blog to use MDX.
W will use the Gatsby Starter Blog
as the basis for our conversion. You can install that using the following Gatsby command;
gatsby new gatsby-blog https://github.com/gatsbyjs/gatsby-starter-blog
You will need to add the mdx plugins to your gatsby site before you make any code changes. Here is the NPM command to add the MDX plugins.
> npm install --save gatsby-plugin-mdx gatsby-plugin-feed-mdx @mdx-js/mdx @mdx-js/react
In your gatsby-config.json
file, we will replace the gatsby-transformer-remark
config with the gatsby-plugin-mdx
config setting. Under options you will need to add property for the extensions
and change the name of the plugins
property to gatsbyRemarkPlugins
. The final configuration should look like the following example.
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.mdx`, `.md`, `.markdown`],
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
},
},
{
resolve: `gatsby-remark-responsive-iframe`,
options: {
wrapperStyle: `margin-bottom: 1.0725rem`,
},
},
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
`gatsby-remark-smartypants`,
],
},
},
Then replace the gatsby-plugin-feed
plugin in the config with gatsby-plugin-feed-mdx
. Once you are done making your configuration changes, you can remove the old NPM modules.
> npm uninstall --save gatsby-transformer-remark gatsby-plugin-feed
Changing Node API
There are some changes we will need to make to the gatsby-node.js
file. We will need to replace any references to allMarkdownRemark
to allMdx
. We will also need to change any reference types that are using MarkdownRemark
to us Mdx
instead.
- allMarkdownRemark(
+ allMdx(
...
- const posts = result.data.allMarkdownRemark.edges
+ const posts = result.data.allMdx.edges
...
- if (node.internal.type === `MarkdownRemark`) {
+ if (node.internal.type === `Mdx`) {
Changing any page reference to Markdown
Now that we have changed the Node API to use Mdx, we can focus on changing any pages or templates that still have references to MarkdownRemark
to use Mdx
. In the index.js
page we replace all markdown references with Mdx instead.
- const posts = data.allMarkdownRemark.edges
+ const posts = data.allMdx.edges
...
- allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
+ allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
Now we can make these changes to the src/templates/blog-post.js
template, but this time the references will be markdownRemark
and mdx
respectively.
// Add import statement for the MDXRenderer
+ import { MDXRenderer } from "gatsby-plugin-mdx"
...
- const post = this.props.data.markdownRemark
+ const post = this.props.data.mdx
...
- markdownRemark(fields: { slug: { eq: $slug } }) {
+ mdx(fields: { slug: { eq: $slug } }) {
...
- <section dangerouslySetInnerHTML={{ __html: post.html }} />
+ <MDXRenderer>{post.body}</MDXRenderer>
Replace html
with body
in your GraphQL queries once you change the markdownRemark
to mdx
.
mdx(id: { eq: $id }) {
id
excerpt(pruneLength: 160)
body
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
}
}
Now lets’ add a MDX blog post. We will name this file example.mdx
and place it into blog
directory with our other posts.
// example.mdx
---
title: MDX Example
date: "2021-07-03T22:12:03.284Z"
description: "MDX Example"
---
# My first MDX post
This is a post showing MDX in action.
MDX lets you write JSX embedded inside markdown, perfect for technical blogs.
Now lets` create a component for adding Youtube videos to our MDX posts.
import React from "react"
const Youtube = props => (
<div style={{textAlign: 'center'}}>
<iframe
title="YoutubeIframe"
width="700"
height="393"
src={`https://youtube.com/embed/${props.yid}`}
frameBorder={`0`}
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
)
export default Youtube;
Now we can add this component to our MDX post.
// example.mdx
---
title: MDX Example
date: "2021-07-03T22:12:03.284Z"
description: "MDX Example"
---
import Youtube from "../../../src/components/yt.js"
# My first MDX post
This is a post showing MDX in action.
<Youtube yid="jYVM6KOWYBs" />
## MDX
MDX lets you write JSX embedded inside markdown, perfect for technical blogs.
Conclusion
By making some simple changes to our Gatsby blog, we can now use MDX based React components to our blog posts. Now we can start using own components mixed in with our simplified markdown based markup. Now we can do things like add video and audio to our posts with just one React element.