MDX integration with Gatsby for ambitious projects.
npm install gatsby-mdx @mdx-js/mdx @mdx-js/tag
then add gatsby-mdx
to your gatsby-config.js
in the plugins
section.
module.exports = {
siteMetadata: {
title: `My Ambitious Project`
},
plugins: [`gatsby-mdx`]
};
Note: gatsby-mdx
is only compatible with Gatsby version 2 or
newer.
Add an .mdx
file in the src/pages
directory. It "Just Works".
# My first MDX Page
some awesome content
gatsby-mdx
can apply to different file extensions. By default it
conservatively applies to only .mdx
files, but can also be made to apply to
.md
files.
module.exports = {
plugins: [
{
resolve: `gatsby-mdx`,
options: {
extensions: [".mdx", ".md"]
}
}
]
};
MDX supports layouts using the default export as such:
export default ({ children }) => (
<div>
<h1>My Layout</h1>
<div>{children}</div>
</div>
)
# My MDX
some content
or as an import:
import PageLayout from './src/components/page-layout';
export PageLayout
# My MDX
some content
Sometimes you don't want to include the layout in every file, so gatsby-mdx
offers the option to set default layouts in the gatsby-config.js
plugin
config. Set the key to the name
set in the gatsby-source-filesystem
config.
If no matching default layout is found, the default
default layout is used.
You can also set options.defaultLayout
if you only want to use one layout for
all MDX pages.
module.exports = {
siteMetadata: {
title: `Gatsby MDX Kitchen Sink`
},
plugins: [
{
resolve: `gatsby-mdx`,
options: {
defaultLayouts: {
posts: require.resolve("./src/components/posts-layout.js"),
default: require.resolve("./src/components/default-page-layout.js")
}
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`
}
}
]
};
MDX files can be queried with allMdx
on the root query. Like
gatsby-transformer-remark
, this plugin adds fields to the Mdx node including
excerpt
, headings
, timeToRead
, and wordCount
.
All static exports – values that would be valid JSON – are queryable through the
exports
field.
query MDXQuery {
allMdx {
edges {
node {
relativePath
fileAbsolutePath
fileNode {
name
}
timeToRead
frontmatter {
title
}
exports {
author
}
}
}
}
}
Pages can be created programmatically by combining gatsby-source-filesystem
in
gatsby-config.js
with some createPage
calls.
# gatsby-config.js
module.exports = {
plugins: [
`gatsby-mdx`,
{
resolve: "gatsby-source-filesystem",
options: {
name: "posts",
path: `${__dirname}/content/`
}
}
]
};
# gatsby-node.js
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions;
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
allMdx {
edges {
node {
fileAbsolutePath
fileNode {
name
}
}
}
}
}
`
).then(result => {
if (result.errors) {
console.log(result.errors);
reject(result.errors);
}
// Create blog posts pages.
result.data.allMdx.edges.forEach(({ node }) => {
createPage({
path: `/non-page/${node.fileNode.name}`,
component: node.fileAbsolutePath, //blogPost,
context: { absPath: node.absolutePath }
});
});
})
);
});
};
Using MDX, you can replace every HTML element that Markdown renders with a custom implementation. This allows you to use a set of design system components when rendering Markdown.
// src/components/layout.js
import { MDXProvider } from "@mdx-js/tag";
import * as DesignSystem from "your-design-system";
export default function Layout({ children }) {
return (
<MDXProvider
components={{
// Map HTML element tag to React component
h1: DesignSystem.H1,
h2: DesignSystem.H2,
h3: DesignSystem.H3,
// Or define component inline
p: props => <p {...props} style={{ color: "rebeccapurple" }} />
}}
>
{children}
</MDXProvider>
);
}
To make every markdown code block an editable live example, you can pass in a
custom code
element to MDXProvider.
import React, {Component} from "react";
import { LiveProvider, LiveEditor, LiveError, LivePreview } from "react-live";
import { MDXProvider } from '@mdx-js/tag'
const MyCodeComponent = ({ children, ...props }) => (
<LiveProvider code={children}>
<LiveEditor />
<LiveError />
<LivePreview />
</LiveProvider>
);
export default MyPageLayout extends Component {
render() {
return <MDXProvider components={{code: MyCodeComponent}}>
<div>{this.props.children}</div>
</MDXProvider>
}
}
Experimental things could be volatile. Use at your own risk.
To embed mdx-deck presentations in your gatsby site, add mdx deck to your dependencies (in addition to the gatsby-mdx and it's dependencies).
npm install mdx-deck
Add the relevant config to your gatsby-config.js
. In this example,
we use set the required decks
key in the gatsby-mdx plugin config to
point to our folder of slide decks and the filesystem source to point
to our decks folder. We also set a defaultLayout
that wraps every
individual slide.
const path = require("path");
module.exports = {
siteMetadata: {
title: `Gatsby MDX Kitchen Sink`
},
plugins: [
`gatsby-plugin-emotion`,
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-mdx`,
options: {
extensions: [".mdx", ".md"],
decks: [path.resolve("./decks")],
defaultLayouts: {
default: require.resolve("./src/components/default-page-layout.js"),
slides: require.resolve("./src/components/default-slide-layout.js")
}
}
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "slides",
path: `${__dirname}/decks/`
}
},
`gatsby-plugin-offline`
]
};