Using MDX | MDX (original) (raw)

This article explains how to use MDX files in your project. It shows how you can pass props and how to import, define, or pass components. See § Getting started for how to integrate MDX into your project. To understand how the MDX format works, we recommend that you start with § What is MDX.

Contents

How MDX works

An integration compiles MDX syntax to JavaScript. Say we have an MDX document, example.mdx:

input.mdx

export function Thing() {
  return <>World</>
}

# Hello <Thing />

That’s roughly turned into the following JavaScript. The below might help to form a mental model:

output-outline.jsx

/* @jsxRuntime automatic */
/* @jsxImportSource react */

export function Thing() {
  return <>World</>
}

export default function MDXContent() {
  return <h1>Hello <Thing /></h1>
}
function Thing(): JSX.Element
function MDXContent(): JSX.Element
(property) React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
function Thing(): JSX.Element
(property) React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>

Some observations:

The actual output is:

output-actual.js

import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'

export function Thing() {
  return _jsx(_Fragment, {children: 'World'})
}

function _createMdxContent(props) {
  const _components = {h1: 'h1', ...props.components}
  return _jsxs(_components.h1, {children: ['Hello ', _jsx(Thing, {})]})
}

export default function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || {}
  return MDXLayout
    ? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {...props})})
    : _createMdxContent(props)
}
(alias) const Fragment: React.ExoticComponent<React.FragmentProps>
export Fragment

Lets you group elements without a wrapper node.

import { Fragment } from 'react';  
<Fragment>  
  <td>Hello</td>  
  <td>World</td>  
</Fragment>  
// Using the <></> shorthand syntax:  
<>  
  <td>Hello</td>  
  <td>World</td>  
</>  
(alias) const _Fragment: React.ExoticComponent<React.FragmentProps>
import _Fragment

Lets you group elements without a wrapper node.

import { Fragment } from 'react';  
<Fragment>  
  <td>Hello</td>  
  <td>World</td>  
</Fragment>  
// Using the <></> shorthand syntax:  
<>  
  <td>Hello</td>  
  <td>World</td>  
</>  
function jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) function _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) function _jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsxs

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function Thing(): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) const _Fragment: React.ExoticComponent<React.FragmentProps>
import _Fragment

Lets you group elements without a wrapper node.

import { Fragment } from 'react';  
<Fragment>  
  <td>Hello</td>  
  <td>World</td>  
</Fragment>  
// Using the <></> shorthand syntax:  
<>  
  <td>Hello</td>  
  <td>World</td>  
</>  
(property) children: string
function _createMdxContent(props: any): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
(alias) _jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsxs

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(property) children: (string | React.ReactElement<unknown, string | React.JSXElementConstructor<any>>)[]
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function Thing(): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
function MDXContent(props?: {}): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(property) children: React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function _createMdxContent(props: any): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
function _createMdxContent(props: any): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>

Some more observations:

† MDX is not coupled to React. You can also use it with Preact, Vue, Emotion, Theme UI, etc. Both the classic and automatic JSX runtimes are supported.

MDX content

We just saw that MDX files are compiled to components. You can use those components like any other component in your framework of choice. Take this file:

It could be imported and used in a React app like so:

example.jsx

import {createRoot} from 'react-dom/client'
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

const container = document.getElementById('root')
if (!container) throw new Error('Expected `root`')
const root = createRoot(container)
root.render(<Example />)
(alias) function createRoot(container: Container, options?: RootOptions): Root
import createRoot
(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

const container: HTMLElement | null
var document: Document

window.document returns a reference to the document contained in the window.

MDN Reference

(method) Document.getElementById(elementId: string): HTMLElement | null

Returns the first element within node's descendants whose ID is elementId.

MDN Reference

const container: HTMLElement | null
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
(alias) createRoot(container: Container, options?: RootOptions): Root
import createRoot
const container: HTMLElement
(method) Root.render(children: React.ReactNode): void
(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

The main content is exported as the default export. All other values are also exported. Take this example:

example.mdx

export function Thing() {
  return <>World</>
}

# Hello <Thing />

It could be imported in the following ways:

example.js

// A namespace import to get everything:
import * as everything from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(everything) // {Thing: [Function: Thing], default: [Function: MDXContent]}

// Default export shortcut and a named import specifier:
import Content, {Thing} from './example.mdx'
console.log(Content) // [Function: MDXContent]
console.log(Thing) // [Function: Thing]

// Import specifier with another local name:
import {Thing as AnotherName} from './example.mdx'
console.log(AnotherName) // [Function: Thing]
(alias) module "*.mdx"
import everything

An MDX file which exports a JSX component.

The default export of MDX files is a function which takes props and returns a JSX element. MDX files can export other identifiers from within the MDX file as well, either authored manually or automatically through plugins

It’s currently not possible for the other exports to be typed automatically. You can type them yourself with a TypeScript script which augments *.mdx modules. A script file is a file which doesn’t use top-level ESM syntax, but ESM syntax is allowed inside the declared module.

This is typically useful for exports created by plugins. For example:

// mdx-custom.d.ts
declare module '*.mdx' {
  import { Frontmatter } from 'my-frontmatter-types';

  export const frontmatter: Frontmatter;
  export const title: string;
}

The previous example added types to all .mdx files. To define types for a specific MDX file, create a file with the same name but postfixed with .d.ts next to the MDX file.

For example, given the following MDX file my-component.mdx:

export const message = 'world';

# Hello {message}

Create the following file named my-component.mdx.d.ts in the same directory:

export { default } from '*.mdx';

export const message: string;

Note that this overwrites the declare module '*.mdx' { … } types from earlier, which is why you also need to define the default export. You can also define your own default export type to narrow the accepted prop types of this specific file.

It should now be possible to import both the MDX component and the exported constant message.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) module "*.mdx"
import everything

An MDX file which exports a JSX component.

The default export of MDX files is a function which takes props and returns a JSX element. MDX files can export other identifiers from within the MDX file as well, either authored manually or automatically through plugins

It’s currently not possible for the other exports to be typed automatically. You can type them yourself with a TypeScript script which augments *.mdx modules. A script file is a file which doesn’t use top-level ESM syntax, but ESM syntax is allowed inside the declared module.

This is typically useful for exports created by plugins. For example:

// mdx-custom.d.ts
declare module '*.mdx' {
  import { Frontmatter } from 'my-frontmatter-types';

  export const frontmatter: Frontmatter;
  export const title: string;
}

The previous example added types to all .mdx files. To define types for a specific MDX file, create a file with the same name but postfixed with .d.ts next to the MDX file.

For example, given the following MDX file my-component.mdx:

export const message = 'world';

# Hello {message}

Create the following file named my-component.mdx.d.ts in the same directory:

export { default } from '*.mdx';

export const message: string;

Note that this overwrites the declare module '*.mdx' { … } types from earlier, which is why you also need to define the default export. You can also define your own default export type to narrow the accepted prop types of this specific file.

It should now be possible to import both the MDX component and the exported constant message.

(alias) function Content(props: MDXProps): Element
import Content

An function component which renders the MDX content using JSX.

(alias) function Thing(): unknown
import Thing
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function Content(props: MDXProps): Element
import Content

An function component which renders the MDX content using JSX.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function Thing(): unknown
import Thing
function Thing(): unknown
(alias) function AnotherName(): unknown
import AnotherName
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function AnotherName(): unknown
import AnotherName

Props

In § What is MDX, we showed that JavaScript expressions, inside curly braces, can be used in MDX:

example.mdx

import {year} from './data.js'
export const name = 'world'

# Hello {name.toUpperCase()}

The current year is {year}

Instead of importing or defining data within MDX, data can also be passed to MDXContent. The passed data is called props. Take for example:

example.mdx

# Hello {props.name.toUpperCase()}

The current year is {props.year}

This file could be used as:

example.jsx

import React from 'react'
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

// Use a `createElement` call:
console.log(React.createElement(Example, {name: 'Venus', year: 2021}))

// Use JSX:
console.log(<Example name="Mars" year={2022} />)
(alias) namespace React
import React
(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) namespace React
import React
function React.createElement<MDXProps>(type: React.FunctionComponent<MDXProps>, props?: (React.Attributes & MDXProps) | null | undefined, ...children: React.ReactNode[]): React.FunctionComponentElement<MDXProps> (+6 overloads)
(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

Note: Users of the MDX VS Code extension can add type checking of props with a JSDoc comment. See mdx-js/mdx-analyzer for more info.

Components

There is one special prop: components. It takes an object mapping component names to components. Take this example:

example.mdx

# Hello *<Planet />*

It can be imported from JavaScript and passed components like so:

example.jsx

import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

console.log(
  <Example
    components={{
      Planet() {
        return <span style={{color: 'tomato'}}>Pluto</span>
      }
    }}
  />
)

You don’t have to pass components. You can also define or import them within MDX:

example.mdx

import {Box, Heading} from 'rebass'

MDX using imported components!

<Box>
  <Heading>Here’s a heading</Heading>
</Box>

Because MDX files are components, they can also import each other:

example.mdx

import License from './license.md' // Assumes an integration is used to compile markdown -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License />

---

<Contributing />

Here are some other examples of passing components:

example.jsx

console.log(
  <Example
    components={{
      // Map `h1` (`# heading`) to use `h2`s.
      h1: 'h2',
      // Rewrite `em`s (`*like so*`) to `i` with a goldenrod foreground color.
      em(props) {
        return <i style={{color: 'goldenrod'}} {...props} />
      },
      // Pass a layout (using the special `'wrapper'` key).
      wrapper({components, ...rest}) {
        return <main {...rest} />
      },
      // Pass a component.
      Planet() {
        return 'Neptune'
      },
      // This nested component can be used as `<theme.text>hi</theme.text>`
      theme: {
        text(props) {
          return <span style={{color: 'grey'}} {...props} />
        }
      }
    }}
  />
)
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

(property) MDXProps.components?: MDXComponents

This prop may be used to customize how certain components are rendered.

(method) em(props: JSX.IntrinsicElements): JSX.Element
(parameter) props: JSX.IntrinsicElements
(property) React.JSX.IntrinsicElements.i: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(property) React.HTMLAttributes<HTMLElement>.style?: React.CSSProperties | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

Chrome Firefox Safari Edge IE
1 1 1 12 3
(parameter) props: JSX.IntrinsicElements
(property) wrapper?: Component<any>

If a wrapper component is defined, the MDX content will be wrapped inside of it.

(parameter) components: any
(property) React.JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(method) Planet(): string
Type '{ text(props: any): Element; }' is not assignable to type '(NestedMDXComponents | Component<any>) & (Component<JSX.IntrinsicElements> | undefined)'.
  Type '{ text(props: any): Element; }' is not assignable to type 'NestedMDXComponents & (new (props: JSX.IntrinsicElements) => JSX.ElementClass)'.
    Type '{ text(props: any): Element; }' is not assignable to type 'new (props: JSX.IntrinsicElements) => JSX.ElementClass'.
      Type '{ text(props: any): Element; }' provides no match for the signature 'new (props: JSX.IntrinsicElements): JSX.ElementClass'. (2322)
(property) theme: {
    text(props: any): JSX.Element;
}
(method) text(props: any): JSX.Element
(property) React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
(property) React.HTMLAttributes<T>.style?: React.CSSProperties | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

Chrome Firefox Safari Edge IE
1 1 1 12 3

The following keys can be passed in components:

The rules for whether a name in JSX (so x in <x>) is a literal tag name (like h1) or not (like Component) are as follows:

These keys in components and the difference between literal tag names and references is illustrated as follows. With the following MDX:

example.mdx

* [markdown syntax](#alpha)
* <a href="#bravo">JSX with a lowercase name</a>
* <Link to="#charlie">JSX with a capitalized name</Link>

…passed some components:

example.jsx

import Example from './example.mdx'

console.log(
  <Example
    components={{
      a(props) {
        return <a {...props} style={{borderTop: '1px dotted', color: 'violet'}} />
      },
      Link(props) {
        return <a href={props.to} children={props.children} style={{borderTop: '1px dashed', color: 'tomato'}} />
      }
    }}
  />
)
(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function Example(props: MDXProps): Element
import Example

An function component which renders the MDX content using JSX.

(property) MDXProps.components?: MDXComponents

This prop may be used to customize how certain components are rendered.

(method) a(props: JSX.IntrinsicElements): JSX.Element
(parameter) props: JSX.IntrinsicElements
(property) React.JSX.IntrinsicElements.a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(parameter) props: JSX.IntrinsicElements
(property) React.HTMLAttributes<HTMLAnchorElement>.style?: React.CSSProperties | undefined
(property) StandardShorthandProperties<string | number, string & {}>.borderTop?: Property.BorderTop<string | number> | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

Chrome Firefox Safari Edge IE
1 1 1 12 3
(method) Link(props: JSX.IntrinsicElements): JSX.Element
(parameter) props: JSX.IntrinsicElements
(property) React.JSX.IntrinsicElements.a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(property) React.AnchorHTMLAttributes<HTMLAnchorElement>.href?: string | undefined
(parameter) props: JSX.IntrinsicElements
(property) React.DOMAttributes<HTMLAnchorElement>.children?: React.ReactNode
(parameter) props: JSX.IntrinsicElements
(property) React.HTMLAttributes<HTMLAnchorElement>.style?: React.CSSProperties | undefined
(property) StandardShorthandProperties<string | number, string & {}>.borderTop?: Property.BorderTop<string | number> | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

Chrome Firefox Safari Edge IE
1 1 1 12 3

…we’d get:

Observe that the first link (#alpha) is dotted and violet. That’s because a is the HTML equivalent for the markdown syntax being used. The second link (#bravo) remains unchanged, because in JSX syntax a is a literal tag name. The third link (#charlie) is dashed and tomato, because in JSX syntax Link is a reference.

Layout

There is one special component: the layout. If it is defined, it’s used to wrap all content. A layout can be defined from within MDX using a default export:

MDX

export default function Layout({children}) {
  return <main>{children}</main>;
}

All the things.

The layout can also be imported and then exported with an export … from:

MDX

export {Layout as default} from './components.js'

The layout can also be passed as components.wrapper (but a local one takes precedence).

MDX provider

You probably don’t need a provider. Passing components is typically fine. Providers often only add extra weight. Take for example this file:

Used like so:

app.jsx

import {createRoot} from 'react-dom/client'
import {Heading, /* … */ Table} from './components.js'
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

const components = {
  h1: Heading.H1,
  // …
  table: Table
}

const container = document.getElementById('root')
if (!container) throw new Error('Expected `root`')
const root = createRoot(container)
root.render(<Post components={components} />)
(alias) function createRoot(container: Container, options?: RootOptions): Root
import createRoot
(alias) const Heading: {
    H1: React.ComponentType;
}
import Heading
(alias) const Table: React.ComponentType<{}>
import Table
(alias) function Post(props: MDXProps): Element
import Post

An function component which renders the MDX content using JSX.

const components: {
    h1: React.ComponentType<{}>;
    table: React.ComponentType<{}>;
}
(property) h1: React.ComponentType<{}>
(alias) const Heading: {
    H1: React.ComponentType;
}
import Heading
(property) H1: React.ComponentType<{}>
(property) table: React.ComponentType<{}>
(alias) const Table: React.ComponentType<{}>
import Table
const container: HTMLElement | null
var document: Document

window.document returns a reference to the document contained in the window.

MDN Reference

(method) Document.getElementById(elementId: string): HTMLElement | null

Returns the first element within node's descendants whose ID is elementId.

MDN Reference

const container: HTMLElement | null
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
(alias) createRoot(container: Container, options?: RootOptions): Root
import createRoot
const container: HTMLElement
(method) Root.render(children: React.ReactNode): void
(alias) function Post(props: MDXProps): Element
import Post

An function component which renders the MDX content using JSX.

(property) MDXProps.components?: MDXComponents

This prop may be used to customize how certain components are rendered.

const components: {
    h1: React.ComponentType<{}>;
    table: React.ComponentType<{}>;
}

That works, those components are used.

But when you’re nesting MDX files (importing them into each other) it can become cumbersome. Like so:

post.mdx

import License from './license.md' // Assumes an integration is used to compile markdown -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License components={props.components} />

---

<Contributing components={props.components} />

To solve this, a context can be used in React, Preact, and Vue. Context provides a way to pass data through the component tree without having to pass props down manually at every level. Set it up like so:

  1. Install either @mdx-js/react, @mdx-js/preact, or @mdx-js/vue, depending on what framework you’re using
  2. Configure your MDX integration with providerImportSource in ProcessorOptions set to that package, so either '@mdx-js/react', '@mdx-js/preact', or '@mdx-js/vue'
  3. Import MDXProvider from that package. Use it to wrap your top-most MDX content component and pass it your components instead:

Diff

+import {MDXProvider} from '@mdx-js/react'
 import {createRoot} from 'react-dom/client'
 import {Heading, /* … */ Table} from './components/index.js'
 import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.
@@ -13,4 +14,8 @@ const components = {

 const container = document.getElementById('root')
 if (!container) throw new Error('Expected `root`')
 const root = createRoot(container)
-root.render(<Post components={components} />)
+root.render(
+  <MDXProvider components={components}>
+    <Post />
+  </MDXProvider>
+)

Now you can remove the explicit and verbose component passing:

Diff

 import License from './license.md' // Assumes an integration is used to compile markdown -> JS.
 import Contributing from './docs/contributing.mdx'

 # Hello world

-<License components={props.components} />
+<License />

 ---

-<Contributing components={props.components} />
+<Contributing />

When MDXProviders are nested, their components are merged. Take this example:

JavaScript

console.log(
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider components={{h2: Component3, h3: Component4}}>
      <Content />
    </MDXProvider>
  </MDXProvider>
)
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h1: React.ComponentType<{}>
(alias) const Component1: React.ComponentType<{}>
import Component1
(property) h2: React.ComponentType<{}>
(alias) const Component2: React.ComponentType<{}>
import Component2
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h2: React.ComponentType<{}>
(alias) const Component3: React.ComponentType<{}>
import Component3
(property) h3: React.ComponentType<{}>
(alias) const Component4: React.ComponentType<{}>
import Component4
(alias) const Content: MDXContent
import Content
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

…which results in h1s using Component1, h2s using Component3, and h3s using Component4.

To merge differently or not at all, pass a function to components. It’s given the current context components and what it returns will be used instead. In this example the current context components are discarded:

JavaScript

console.log(
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider
      components={
        function () {
          return {h2: Component3, h3: Component4}
        }
      }
    >
      <Content />
    </MDXProvider>
  </MDXProvider>
)
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h1: React.ComponentType<{}>
(alias) const Component1: React.ComponentType<{}>
import Component1
(property) h2: React.ComponentType<{}>
(alias) const Component2: React.ComponentType<{}>
import Component2
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h2: React.ComponentType<{}>
(alias) const Component3: React.ComponentType<{}>
import Component3
(property) h3: React.ComponentType<{}>
(alias) const Component4: React.ComponentType<{}>
import Component4
(alias) const Content: MDXContent
import Content
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

…which results in h2s using Component3 and h3s using Component4. No component is used for h1.

If you’re not nesting MDX files, or not nesting them often, don’t use providers: pass components explicitly.