Skip to main content

Getting Started

Table of contents#

Hello World#

The smallest MDX example looks like this:

It displays a heading saying “Hello, world!” on the page. You could also write it like so:

## Hello, world!

This displays the same heading.

<h2>Hello, world!</h2>

Syntax#

MDX syntax can be boiled down to being JSX in Markdown. It’s a superset of Markdown syntax that also supports importing, exporting, and JSX.

Markdown#

Traditionally, Markdown is used to generate HTML. Many developers like writing markup in Markdown as it often looks more like what’s intended and it is typically terser. Instead of the following HTML:

<blockquote>
<p>A blockquote with <em>some</em> emphasis.</p>
</blockquote>

You can write the equivalent in Markdown (or MDX) like so:

> A blockquote with _some_ emphasis.

Markdown is good for content. MDX supports standard Markdown syntax. It’s important to understand Markdown in order to learn MDX.

JSX#

Recently, more and more developers have started using JSX to generate HTML markup. JSX is typically combined with a frontend framework like React or Vue. These frameworks add support for components, which let you change repeating things like the following markup:

<h2>Hello, Venus!</h2>
<h2>Hello, Mars!</h2>

…to JSX (or MDX) like this:

<Welcome name="Venus" />
<Welcome name="Mars" />

JSX is good for components. It makes repeating things more clear and allows for separation of concerns. MDX fully supports JSX syntax. Any line that start with the < character starts a JSX block.

MDX#

We love HTML, but we’ve created MDX to let you combine the benefits of Markdown with the benefits of JSX. The following example shows how they can be combined. It’s interactive so go ahead and change the code!

Below is a JSX block:

<div style={{ padding: "10px 30px", backgroundColor: "tomato" }}>
<h2>Try making this heading have the color green</h2>
</div>

MDX supports two more features: imports and exports.

Imports#

import (ES2015)can be used to import components, data, and documents.

Components#

You can import components, such as your own or from rebass, like so:

import { Box, Heading, Text } from 'rebass'
# Here is a JSX block
It is using imported components!
<Box>
<Heading>Here's a JSX block</Heading>
<Text>It's pretty neat</Text>
</Box>
Data#

You can also import data that you want to display:

import snowfallData from './snowfall.json'
import BarChart from './charts/BarChart'
# Recent snowfall trends
<p>
2019 has been a particularly snowy year when compared to the last decade.
</p>
<BarChart data={snowfallData} />
Documents#

You can embed MDX documents in other documents. This is also known as transclusion. You can achieve this by importing an .mdx (or .md) file:

import License from './license.md'
import Contributing from './docs/contributing.mdx'
# Hello, world!
<License />
---
<Contributing />
Exports#

export (ES2015) can be used to export data and components. For example, you can export metadata like which layout to use or the authors of a document. It’s a mechanism for an imported MDX file to communicate with the thing that imports it.

Say we import our MDX file, using webpack and React, like so:

index.js
import React from "react";
import MDXDocument, { metadata } from "posts/post.mdx";
export default () => (
<>
<MDXDocument />
<footer>
<p>
By: {metadata.authors.map((author) => author.name).join(", ") + "."}
</p>
</footer>
</>
);

And our MDX file looks as follows (note the export):

posts/post.mdx
import { sue, fred } from '../data/authors'
export const metadata = {
authors: [sue, fred]
}
# Post about MDX
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.

After bundling and evaluating, we could get something like this:

<h1>Post about MDX</h1>
<p>
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.
</p>
<footer>
<p>By: Sue, Fred.</p>
</footer>

This is similar to what frontmatter allows in Markdown, but instead of supporting only data in something like YAML, MDX lets you use richer JavaScript structures.

Defining variables with exports#

If you need to define a variable in your MDX document, you can use an export to do so. Not only do exports emit data, they instantiate data you can reference in JSX blocks:

export const myVariable = "Yay!";
# Hello, world!
<div>{myVariable}</div>

Working with components#

In addition to rendering components inline, you can also pass in components to be used instead of the default HTML elements that Markdown compiles to. This allows you to use your existing components and even CSS-in-JS like styled-components .

The components object is a mapping between the HTML name and the desired component you’d like to render.

src/App.js
import React from "react";
import Hello from "../hello.mdx";
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 default () => <Hello components={components} />;

You can also import your components from another location like your UI library:

import React from "react";
import Hello from "../hello.mdx";
import { Text, Heading, Code, InlineCode } from "../my-ui-library";
export default () => (
<Hello
components={{
h1: Heading,
p: Text,
code: Code,
inlineCode: InlineCode,
}}
/>
);

With the above, the Heading component will be rendered for any h1, Text for p elements, and so on.

In addition to HTML elements, there is one special mapping: inlineCode can be used for code inside paragraphs, tables, etc.

See the Table of components for supported names.

MDXProvider#

If you’re using an app layout that wraps your application, you can use the MDXProvider to only pass your components in one place:

src/App.js
import React from "react";
import { MDXProvider } from "@mdx-js/react";
import { Heading, Text, Pre, Code, Table } from "./components";
const components = {
h1: Heading.H1,
h2: Heading.H2,
// …
p: Text,
code: Pre,
inlineCode: Code,
};
export default (props) => (
<MDXProvider components={components}>
<main {...props} />
</MDXProvider>
);

This allows you to remove duplicated component passing and importing. It will typically go in layout files.

Using the wrapper#

The MDXProvider has a special wrapper key that you can use in the component mapping. With your wrapper component you can set the layout of your document, inject styling, or even manipulate the children passed to the component.

src/App.js
import React from "react";
import { MDXProvider } from "@mdx-js/react";
const Wrapper = (props) => (
<main style={{ padding: "20px", backgroundColor: "tomato" }} {...props} />
);
export default ({ children }) => (
<MDXProvider components={{ wrapper: Wrapper }}>{children}</MDXProvider>
);

Default exports#

Sometimes from an MDX file you might want to override the wrapper. This is especially useful when you want to override layout for a single entry point at the page level. To achieve this you can use the ES default export and it will wrap your MDX document instead of the wrapper passed to MDXProvider.

You can declare a default export as a function:

import Layout from "./Layout";
export default ({ children }) => <Layout some="metadata">{children}</Layout>;
# Hello, world!

Or directly as a component:

import Layout from "./Layout";
export default Layout;
# Hello, world!

Either works. Whatever you prefer!