Skip to main content
View plugin on GitHub
See starters using this

Logo

gatsby-mdx is the official integration for using MDX with Gatsby.

What’s MDX?

MDX is markdown for the component era. It lets you write JSX embedded inside markdown. It’s a great combination because it allows you to use markdown’s often terse syntax (such as # heading) for the little things and JSX for more advanced components.

Read more about MDX

Table of contents

Installation

Install with npm:

npm install --save gatsby-mdx @mdx-js/mdx @mdx-js/tag

Install with yarn:

yarn add gatsby-mdx @mdx-js/mdx @mdx-js/tag

Usage

After installing gatsby-mdx you can add it to your plugins list in your gatsby-config.js.

module.exports = {
  plugins: [`gatsby-mdx`]
};

By default, this configuration will allow you to create pages with .mdx files in src/pages and will process any Gatsby nodes with Markdown media types into MDX content.

Configuration

gatsby-mdx exposes a configuration API that can be used similarly to any other Gatsby plugin. You can define MDX extensions, layouts, global scope, and more.

Key Default Description
extensions [".mdx"] Configure the file extensions that gatsby-mdx will process
defaultLayouts {} Set the layout components for MDX source types
globalScope "" Define components and variables that are accessible to all MDX files
`gatsbyRemarkPlugins | [] | Use Gatsby-specific remark plugins
mdPlugins [] Specify remark plugins
hastPlugins [] Specify rehype plugins
mediaTypes ["text/markdown", "text/x-markdown"] Determine which media types are processed by MDX

Extensions

By default, only files with the .mdx file extension are treated as MDX when using gatsby-source-filesystem. To use .md or other file extensions, you can define an array of file extensions in the gatsby-mdx section of your gatsby-config.js.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        extensions: [`.mdx`, `.md`]
      }
    }
  ]
};

Default layouts

defaultLayouts takes an object where the key is the name key of the gatsby-source-filesystem configuration you want to target. default applies to any MDX file that doesn’t already have a layout defined, even if it’s imported manually using import MDX from './thing.mdx.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        defaultLayouts: {
          posts: require.resolve("./src/components/posts-layout.js"),
          default: require.resolve("./src/components/default-page-layout.js")
        }
      }
    }
  ]
};

MDX has the concept of a layout that is different than the Gatsby concept of a layout. MDX’s layouts are written using the default export JavaScript syntax in a single MDX file. An MDX layout will wrap the MDX content in an additional component, so this can be a good place for page layout depending on how you are using MDX.

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 default 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.default if you only want to use one layout for all MDX pages that don’t already have a layout defined.

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/`
      }
    }
  ]
};

Global scope

When importing a react component into your MDX, you can import it using the import statement as in JavaScript.

import { SketchPicker } from "react-color";

# Hello, world!

Here's a color picker!

<SketchPicker />

If you want to allow usage of a component from anywhere, add it to the globalScope field in the options inside gatsby-config.js:

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        globalScope: `
          import { SketchPicker } from "react-color";

          export default { SketchPicker };
        `
      }
    }
  ]
};

All that is needed is to import the components you wish to be globally available and then put them into an exported object.

Then, in any MDX file, you can insert the components without the import.

# Hello, world!

Here's a color picker

<SketchPicker />

:warning: Note: globalScope is not working yet in any mdx file in src/pages, but there is an issue to resolve this:

ChristopherBiscardi/gatsby-mdx#239

Gatsby remark plugins

This config option is used for compatibility with a set of plugins many people use with remark that require the gatsby environment to function properly. In some cases, like gatsby-remark-prismjs, it makes more sense to use a library like prism-react-renderer to render codeblocks using a React component. In other cases, like gatsby-remark-images, the interaction with the Gatsby APIs is well deserved because the images can be optimized by Gatsby and you should continue using it.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590
            }
          }
        ]
      }
    }
  ]
};
Note:

Using a string reference is currently not supported for gatsbyRemarkPlugins. (A PR would be accepted for this)

gatsbyRemarkPlugins: [`gatsby-remark-images`];

MD plugins

This is a configuration option that is mirrored from the core MDX processing pipeline. It enables the use of remark plugins for processing MDX content.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        mdPlugins: [require("remark-abbr")]
      }
    }
  ]
};

HAST plugins

This is a configuration option that is mirrored from the core MDX processing pipeline. It enables the use of rehype plugins for processing MDX content.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        hastPlugins: [require("rehype-slug")]
      }
    }
  ]
};

Media types

Deciding what content gets processed by gatsby-mdx. This is an advanced option that is useful for dealing with specialized generated content. It is not intended to be configured for most users.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-mdx`,
      options: {
        mediaTypes: [`text/markdown`, `text/x-markdown`]
      }
    }
  ]
};
Explanation

Gatsby includes the media-type of the content on any given node. For file nodes, we choose whether to process the content with MDX or not by the file extension. For remote content or generated content, we choose which nodes to process by looking at the media type.

Components

MDX and gatsby-mdx use components for different things like rendering and component mappings.

MDXProvider

MDXProvider is a React component that allows you to replace the rendering of tags in MDX content. It does this by providing a list of components via context to the internal MDXTag component that handles rendering of base tags like p and h1. There are two special tags that can be replaced too: inlineCode and wrapper. inlineCode is for inline <code> and wrapper is the special element that wraps all of the MDX content.

import { MDXProvider } from "@mdx-js/tag";

const MyH1 = props => <h1 style={{ color: "tomato" }} {...props} />;
const MyParagraph = props => (
  <p style={{ fontSize: "18px", lineHeight: 1.6 }} />
);

const components = {
  h1: MyH1,
  p: MyParagraph
};

export const wrapRootElement = ({ element }) => (
  <MDXProvider components={components}>{element}</MDXProvider>
);

The following components can be customized with the MDXProvider:

Tag Name Syntax
p Paragraph
h1 Heading 1 #
h2 Heading 2 ##
h3 Heading 3 ###
h4 Heading 4 ####
h5 Heading 5 #####
h6 Heading 6 ######
thematicBreak Thematic break ***
blockquote Blockquote >
ul List -
ol Ordered list 1.
li List item
table Table --- | --- | ---
tr Table row This | is | a | table row
td/th Table cell
pre Pre
code Code
em Emphasis _emphasis_
strong Strong **strong**
delete Delete ~~strikethrough~~
code InlineCode
hr Break ---
a Link <https://mdxjs.com> or [MDX](https://mdxjs.com)
img Image ![alt](https://mdx-logo.now.sh)

It’s important to define the components you pass in in a stable way so that the references don’t change if you want to be able to navigate to a hash. That’s why we defined components outside of any render functions in these examples.

MDXRenderer

MDXRenderer is a React component that takes compiled MDX content and renders it. You will need to use this if your MDX content is coming from a GraphQL page query or StaticQuery.

MDXRenderer takes any prop and passes it on to your MDX content, just like a normal React component.

<MDXRenderer title="My Stuff!">{mdx.code.body}</MDXRenderer>

Using a page query:

import { MDXRenderer } from "gatsby-mdx";

export default class MyPageLayout {
  render() {
    <MDXRenderer>{this.props.data.mdx.code.body}</MDXRenderer>;
  }
}

export const pageQuery = graphql`
  query MDXQuery($id: String!) {
    mdx(id: { eq: $id }) {
      id
      code {
        body
      }
    }
  }
`;

License

MIT


Docs
Tutorials
Plugins
Blog
Showcase