By Titus Wormer
Getting started
This article explains how to integrate MDX into your project. It shows how to use MDX with your bundler and JSX runtime of choice. To understand how the MDX format works, we recommend that you start with § What is MDX. See § Using MDX when you’re all set up and ready to use MDX.
Contents
Prerequisites
MDX relies on JSX, so it’s required that your project supports JSX as well. Any JSX runtime (React, Preact, Vue, etc.) will do. Note that we do compile JSX to JavaScript for you so you don’t have to set that up.
All @mdx-js/* packages are written in modern JavaScript. A Node.js version of 16 or later is needed to use them. Our packages are also ESM only.
Note: Using Rust instead of Node.js? Try mdxjs-rs!
Quick start
Bundler
MDX is a language that’s compiled to JavaScript. (We also compile regular markdown to JavaScript.) The easiest way to get started is to use an integration for your bundler if you have one:
- if you use esbuild (or Bun), install and configure
@mdx-js/esbuild - if you use Rollup (or Vite), install and configure
@mdx-js/rollup - if you use webpack (or Next.js), install and configure
@mdx-js/loader
You can also use MDX without bundlers:
- you can import MDX files in Node.js with
@mdx-js/node-loader - you can use our core compiler
@mdx-js/mdxto compile MDX files - you can use our core compiler
@mdx-js/mdxto evaluate (compile and run) MDX files
For more info on these tools, see their dedicated sections: ¶ Next.js, ¶ Node.js, ¶ Rollup, ¶ Vite, ¶ esbuild, and ¶ webpack.
JSX
Now you’ve set up an integration or @mdx-js/mdx itself, it’s time to configure your JSX runtime.
- if you use React, that’s the default; optionally install and configure
@mdx-js/react - if you use Preact, set
jsxImportSourceinProcessorOptionsto'preact'; optionally install and configure@mdx-js/preact - if you use Svelte, install
svelte-jsx, and setjsxImportSourceinProcessorOptionsto'svelte-jsx' - if you use Vue, set
jsxImportSourceinProcessorOptionsto'vue'; optionally install and configure@mdx-js/vue - if you use Solid, set
jsxImportSourceinProcessorOptionsto'solid-js/h' - if you use Emotion, set
jsxImportSourceinProcessorOptionsto'@emotion/react' - if you use Theme UI, install and configure
@mdx-js/react, then wrap your MDX content in a<ThemeProvider />
Other JSX runtimes are supported by setting jsxImportSource in ProcessorOptions.
For more info on these tools, see their dedicated sections: ¶ Emotion, ¶ Preact, ¶ React, ¶ Solid, ¶ Svelte, ¶ Theme UI, and ¶ Vue.
Editor
You can enhance the experience of using MDX by adding support of it to your editor:
- if you use VS Code, try
mdx-js/mdx-analyzer - if you use Vim, try
jxnblk/vim-mdx-js - if you use Sublime Text, try
jonsuh/mdx-sublime - if you use JetBrains IntelliJ/WebStorm, try
JetBrains/mdx-intellij-plugin
The syntax highlighting that powers our VS Code extension and that is used to highlight code blocks on GitHub is maintained at wooorm/markdown-tm-language.
Types
Expand example of typed imports
First install the package:
npm install @types/mdx
…TypeScript should automatically pick it up:
import Post from './post.mdx' // `Post` is now typed.
(alias) function Post(props: MDXProps): Element
import PostAn function component which renders the MDX content using JSX.
- @param props This value is be available as the named variable
propsinside the MDX component. - @returns A JSX element. The meaning of this may depend on the project configuration. I.e. it could be a React, Preact, or Vuex element.
Our packages are typed with TypeScript. For types to work, the JSX namespace must be typed. This is done by installing and using the types of your framework, such as @types/react.
To enable types for imported .mdx, .md, etc., install and use @types/mdx. This package also exports several useful types, such as MDXComponents which represents the components prop. You can import them like so:
import type {MDXComponents} from 'mdx/types.js'
(alias) type MDXComponents = NestedMDXComponents & {
[x: string]: Component<JSX.IntrinsicElements> | undefined;
} & {
wrapper?: Component<any>;
}
import MDXComponentsMDX components may be passed as the components.
The key is the name of the element to override. The value is the component to render instead.
Security
MDX is a programming language. If you trust your authors, that’s fine. If you don’t, it’s unsafe.
Do not let random people from the internet write MDX. If you do, you might want to look into using <iframe>s with sandbox, but security is hard, and that doesn’t seem to be 100%. For Node.js, vm2 sounds interesting. But you should probably also sandbox the whole OS using Docker or similar, perform rate limiting, and make sure processes can be killed when taking too long.
Integrations
Bundlers
esbuild
Expand example
import mdx from '@mdx-js/esbuild'
import esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['index.mdx'],
format: 'esm',
outfile: 'output.js',
plugins: [mdx({/* jsxImportSource: …, otherOptions… */})]
})
(alias) function mdx(options?: Readonly<Options> | null | undefined): esbuild.Plugin
import mdxCreate an esbuild plugin to compile MDX to JS.
esbuild takes care of turning modern JavaScript features into syntax that works wherever you want it to. With other integrations you might need to use Babel for this, but with esbuild that’s not needed. See esbuild’s docs for more info.
- @param options Configuration (optional).
- @return Plugin.
import esbuildimport esbuildfunction build<{
entryPoints: string[];
format: "esm";
outfile: string;
plugins: esbuild.Plugin[];
}>(options: esbuild.SameShape<esbuild.BuildOptions, {
entryPoints: string[];
format: "esm";
outfile: string;
plugins: esbuild.Plugin[];
}>): Promise<esbuild.BuildResult<{
entryPoints: string[];
format: "esm";
outfile: string;
plugins: esbuild.Plugin[];
}>>This function invokes the "esbuild" command-line tool for you. It returns a promise that either resolves with a "BuildResult" object or rejects with a "BuildFailure" object.
- Works in node: yes
- Works in browser: yes
Documentation: https://esbuild.github.io/api/#build
(property) entryPoints: string[](property) format: "esm"(property) outfile: string(property) plugins: esbuild.Plugin[](alias) mdx(options?: Readonly<Options> | null | undefined): esbuild.Plugin
import mdxCreate an esbuild plugin to compile MDX to JS.
esbuild takes care of turning modern JavaScript features into syntax that works wherever you want it to. With other integrations you might need to use Babel for this, but with esbuild that’s not needed. See esbuild’s docs for more info.
- @param options Configuration (optional).
- @return Plugin.
We support esbuild. Install and configure the esbuild plugin @mdx-js/esbuild. Configure your JSX runtime depending on which one (React, Preact, Vue, etc.) you use.
To use more modern JavaScript features than what your users support, configure esbuild’s target.
See also ¶ Bun, which you might be using, for more info.
Rollup
Expand example
/**
* @import {RollupOptions} from 'rollup'
*/
import mdx from '@mdx-js/rollup'
import {babel} from '@rollup/plugin-babel'
/** @type {RollupOptions} */
const config = {
// …
plugins: [
// …
mdx({/* jsxImportSource: …, otherOptions… */}),
// Babel is optional:
babel({
// Also run on what used to be `.mdx` (but is now JS):
extensions: ['.js', '.jsx', '.cjs', '.mjs', '.md', '.mdx'],
// Other options…
})
]
}
export default config
(alias) function mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdxPlugin to compile MDX w/ rollup.
- @param options Configuration (optional).
- @return Rollup plugin.
(alias) function babel(options?: RollupBabelInputPluginOptions): Plugin
import babelA Rollup plugin for seamless integration between Rollup and Babel.
- @param options - Plugin options.
- @returns Plugin instance.
const config: RollupOptions- @type {RollupOptions}
(property) InputOptions.plugins?: InputPluginOption(alias) mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdxPlugin to compile MDX w/ rollup.
- @param options Configuration (optional).
- @return Rollup plugin.
(alias) babel(options?: RollupBabelInputPluginOptions): Plugin
import babelA Rollup plugin for seamless integration between Rollup and Babel.
- @param options - Plugin options.
- @returns Plugin instance.
(property) RollupBabelInputPluginOptions.extensions?: string[]An array of file extensions that Babel should transpile. If you want to transpile TypeScript files with this plugin it's essential to include .ts and .tsx in this option.
- @default ['.js', '.jsx', '.es6', '.es', '.mjs']
const config: RollupOptions- @type {RollupOptions}
We support Rollup. Install and configure the Rollup plugin @mdx-js/rollup. Configure your JSX runtime depending on which one (React, Preact, Vue, etc.) you use.
To use more modern JavaScript features than what your users support, install and configure @rollup/plugin-babel.
See also ¶ Vite, if you use Rollup through it, for more info.
Webpack
Expand example
/**
* @import {Options} from '@mdx-js/loader'
* @import {Configuration} from 'webpack'
*/
/** @type {Configuration} */
const webpackConfig = {
module: {
// …
rules: [
// …
{
test: /\.mdx?$/,
use: [
// Babel is optional:
{loader: 'babel-loader', options: {}},
{
loader: '@mdx-js/loader',
/** @type {Options} */
options: {/* jsxImportSource: …, otherOptions… */}
}
]
}
]
}
}
export default webpackConfig
const webpackConfig: Configuration- @type {Configuration}
(property) Configuration.module?: ModuleOptionsOptions affecting the normal modules (NormalModuleFactory).
(property) ModuleOptions.rules?: (false | "" | 0 | RuleSetRule | "..." | null | undefined)[]An array of rules applied for modules.
(property) RuleSetRule.test?: string | RegExp | ((value: string) => boolean) | RuleSetLogicalConditionsAbsolute | RuleSetConditionAbsolute[]Shortcut for resource.test.
(property) RuleSetRule.use?: string | RuleSetUseFunction | (string | false | 0 | RuleSetUseFunction | {
ident?: string;
loader?: string;
options?: string | {
[index: string]: any;
};
} | null | undefined)[] | {
ident?: string;
loader?: string;
options?: string | {
[index: string]: any;
};
}Modifiers applied to the module when rule is matched.
(property) loader?: stringLoader name.
(property) options?: string | {
[index: string]: any;
}Loader options.
(property) loader?: stringLoader name.
(property) options?: string | {
[index: string]: any;
}Loader options.
const webpackConfig: Configuration- @type {Configuration}
We support webpack. Install and configure the webpack loader @mdx-js/loader. Configure your JSX runtime depending on which one (React, Preact, Vue, etc.) you use.
To use more modern JavaScript features than what your users support, install and configure babel-loader.
See also ¶ Next.js, if you use webpack through it, for more info.
Build systems
Vite
Expand example
import mdx from '@mdx-js/rollup'
import {defineConfig} from 'vite'
const viteConfig = defineConfig({
plugins: [
mdx(/* jsxImportSource: …, otherOptions… */)
]
})
export default viteConfig
(alias) function mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdxPlugin to compile MDX w/ rollup.
- @param options Configuration (optional).
- @return Rollup plugin.
(alias) function defineConfig(config: UserConfig): UserConfig (+5 overloads)
import defineConfigType helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
const viteConfig: UserConfig(alias) defineConfig(config: UserConfig): UserConfig (+5 overloads)
import defineConfigType helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
(property) UserConfig.plugins?: PluginOption[]Array of vite plugins to use.
(alias) mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdxPlugin to compile MDX w/ rollup.
- @param options Configuration (optional).
- @return Rollup plugin.
const viteConfig: UserConfigWe support Vite. Install and configure the Rollup plugin @mdx-js/rollup. Configure your JSX runtime depending on which one (React, Preact, Vue, etc.) you use.
To use more modern JavaScript features than what your users support, configure Vite’s build.target.
Note: If you also use @vitejs/plugin-react, you must force @mdx-js/rollup to run in the pre phase before it:
// …
const viteConfig = defineConfig({
plugins: [
{enforce: 'pre', ...mdx({/* jsxImportSource: …, otherOptions… */})},
react({include: /\.(jsx|js|mdx|md|tsx|ts)$/})
]
})
// …
const viteConfig: UserConfig(alias) defineConfig(config: UserConfig): UserConfig (+5 overloads)
import defineConfigType helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
(property) UserConfig.plugins?: PluginOption[]Array of vite plugins to use.
(property) Plugin$1<any>.enforce?: "pre" | "post"Enforce plugin invocation tier similar to webpack loaders. Hooks ordering is still subject to the order property in the hook object.
Plugin invocation order:
- alias resolution
enforce: 'pre'plugins- vite core plugins
- normal plugins
- vite build plugins
enforce: 'post'plugins- vite build post plugins
(alias) mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdxPlugin to compile MDX w/ rollup.
- @param options Configuration (optional).
- @return Rollup plugin.
(alias) react(opts?: Options): Plugin$1[]
import react(property) Options.include?: string | RegExp | (string | RegExp)[]See also ¶ Rollup which is used in Vite and see ¶ Vue if you’re using that, for more info.
Compilers
Babel
Expand plugin and sample use
This plugin:
/**
* @import {ParseResult, ParserOptions} from '@babel/parser'
* @import {File} from '@babel/types'
* @import {Program} from 'estree'
* @import {Plugin} from 'unified'
*/
import parser from '@babel/parser'
import {compileSync} from '@mdx-js/mdx'
import estreeToBabel from 'estree-to-babel'
/**
* Plugin that tells Babel to use a different parser.
*/
export function babelPluginSyntaxMdx() {
return {parserOverride: babelParserWithMdx}
}
/**
* Parser that handles MDX with `@mdx-js/mdx` and passes other things through
* to the normal Babel parser.
*
* @param {string} value
* @param {ParserOptions} options
* @returns {ParseResult<File>}
*/
function babelParserWithMdx(value, options) {
/** @type {string | undefined} */
// @ts-expect-error: babel changed the casing at some point and the types are out of date.
const filename = options.sourceFilename || options.sourceFileName
if (filename && /\.mdx?$/.test(filename)) {
// Babel does not support async parsers, unfortunately.
const file = compileSync(
{value, path: options.sourceFilename},
{recmaPlugins: [recmaBabel] /* jsxImportSource: …, otherOptions… */}
)
return /** @type {ParseResult<File>} */ (file.result)
}
return parser.parse(value, options)
}
/**
* A “recma” plugin is a unified plugin that runs on the estree (used by
* `@mdx-js/mdx` and much of the JS ecosystem but not Babel).
* This plugin defines `'estree-to-babel'` as the compiler,
* which means that the resulting Babel tree is given back by `compileSync`.
*
* @type {Plugin<[], Program, unknown>}
*/
function recmaBabel() {
// @ts-expect-error: `Program` is similar enough to a unist node.
this.compiler = compiler
/**
* @param {Program} tree
* @returns {unknown}
*/
function compiler(tree) {
// @ts-expect-error: TS2349: This expression *is* callable, `estreeToBabel` types are wrong.
return estreeToBabel(tree)
}
}
import parser(alias) function compileSync(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): VFile
import compileSyncSynchronously compile MDX to JS.
When possible please use the async compile.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Compiled file.
import estreeToBabelfunction babelPluginSyntaxMdx(): {
parserOverride: (value: string, options: parser.ParserOptions) => parser.ParseResult<File>;
}Plugin that tells Babel to use a different parser.
(property) parserOverride: (value: string, options: parser.ParserOptions) => parser.ParseResult<File>function babelParserWithMdx(value: string, options: parser.ParserOptions): parser.ParseResult<File>Parser that handles MDX with @mdx-js/mdx and passes other things through to the normal Babel parser.
- @param value
- @param options
- @returns
function babelParserWithMdx(value: string, options: parser.ParserOptions): parser.ParseResult<File>Parser that handles MDX with @mdx-js/mdx and passes other things through to the normal Babel parser.
- @param value
- @param options
- @returns
(parameter) value: string- @param value
(parameter) options: Partial<Options>- @param options
const filename: string | undefined- @type {string | undefined}
(parameter) options: Partial<Options>- @param options
(property) sourceFilename?: string | undefinedCorrelate output AST nodes with their source filename. Useful when generating code and source maps from the ASTs of multiple input files.
(parameter) options: Partial<Options>- @param options
anyconst filename: string | undefined- @type {string | undefined}
(method) RegExp.test(string: string): booleanReturns a Boolean value that indicates whether or not a pattern exists in a searched string.
- @param string String on which to perform the search.
const filename: string- @type {string | undefined}
const file: VFile(alias) compileSync(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): VFile
import compileSyncSynchronously compile MDX to JS.
When possible please use the async compile.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Compiled file.
(property) value: string(property) path: string | undefined(parameter) options: Partial<Options>- @param options
(property) sourceFilename?: string | undefinedCorrelate output AST nodes with their source filename. Useful when generating code and source maps from the ASTs of multiple input files.
(property) recmaPlugins?: PluggableList | null | undefinedList of recma plugins (optional).
class recmaBabel
function recmaBabel(this: Processor): void | Transformer<Program, Node> | undefinedA “recma” plugin is a unified plugin that runs on the estree (used by @mdx-js/mdx and much of the JS ecosystem but not Babel). This plugin defines 'estree-to-babel' as the compiler, which means that the resulting Babel tree is given back by compileSync.
- @type {Plugin<[], Program, unknown>}
const file: VFile(property) VFile.result: unknownCustom, non-string, compiled, representation.
This is used by unified to store non-string results. One example is when turning markdown into React nodes.
- @type {unknown}
import parser(alias) parse(input: string, options?: parser.ParserOptions): parser.ParseResult<File>
export parseParse the provided code as an entire ECMAScript program.
(parameter) value: string- @param value
(parameter) options: Partial<Options>- @param options
function recmaBabel(this: Processor): void | Transformer<Program, Node> | undefinedA “recma” plugin is a unified plugin that runs on the estree (used by @mdx-js/mdx and much of the JS ecosystem but not Babel). This plugin defines 'estree-to-babel' as the compiler, which means that the resulting Babel tree is given back by compileSync.
- @type {Plugin<[], Program, unknown>}
(property) recmaBabel.compiler: (tree: Program) => unknown(local function) compiler(tree: Program): unknown- @param tree
- @returns
(local function) compiler(tree: Program): unknown- @param tree
- @returns
(parameter) tree: Program- @param tree
import estreeToBabel(parameter) tree: Program- @param tree
…can be used like so with the Babel API:
import babel from '@babel/core'
import {babelPluginSyntaxMdx} from './plugin.js'
const document = '# Hello, world!'
// Note that a filename must be set for our plugin to know it’s MDX instead of JS.
const result = await babel.transformAsync(document, {
filename: 'example.mdx',
plugins: [babelPluginSyntaxMdx]
})
console.log(result)
import babel(alias) function babelPluginSyntaxMdx(): {
parserOverride: (value: string, options: babel.ParserOptions) => ParseResult<babel.types.File>;
}
import babelPluginSyntaxMdxPlugin that tells Babel to use a different parser.
const document: "# Hello, world!"const result: babel.BabelFileResult | nullimport babelfunction transformAsync(code: string, opts?: babel.TransformOptions): Promise<babel.BabelFileResult | null>Transforms the passed in code. Calling a callback with an object with the generated code, source map, and AST.
const document: "# Hello, world!"(property) TransformOptions.filename?: string | null | undefinedFilename for use in errors etc
Default: "unknown"
(property) TransformOptions.plugins?: babel.PluginItem[] | null | undefinedList of plugins to load and use
Default: []
(alias) function babelPluginSyntaxMdx(): {
parserOverride: (value: string, options: babel.ParserOptions) => ParseResult<babel.types.File>;
}
import babelPluginSyntaxMdxPlugin that tells Babel to use a different parser.
namespace console
var console: ConsoleThe 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:
- A
Consoleclass with methods such asconsole.log(),console.error()andconsole.warn()that can be used to write to any Node.js stream. - A global
consoleinstance configured to write toprocess.stdoutandprocess.stderr. The globalconsolecan be used without importing thenode:consolemodule.
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
- @see source
(method) Console.log(message?: any, ...optionalParams: any[]): voidPrints 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.
- @since v0.1.100
const result: babel.BabelFileResult | nullYou should probably use Rollup or webpack instead of Babel directly as that gives the best interface. It is possible to use @mdx-js/mdx in Babel and it’s a bit faster, as it skips @mdx-js/mdx serialization and Babel parsing, if Babel is used anyway.
Babel does not support syntax extensions to its parser (it has “syntax” plugins but those only turn internal flags on or off). It does support setting a different parser. Which in turn lets us choose whether to use the @mdx-js/mdx or @babel/parser.
Site generators
Astro
Astro has its own MDX integration. You can add the integration with the Astro CLI: npx astro add mdx.
This base setup lets you import markdown, Astro components, and MDX files as components. See Astro’s Framework components guide for info on how to use components from frameworks in your MDX files.
For more on how to combine Astro and MDX, see Astro’s MDX integration docs.
Docusaurus
Docusaurus supports MDX by default. See Docusaurus’ MDX and React guide for info on how to use MDX with Docusaurus.
Gatsby
Gatsby has its own plugin to support MDX. See gatsby-plugin-mdx on how to use MDX with Gatsby.
Next.js
Expand example
import nextMdx from '@next/mdx'
const withMdx = nextMdx({
// By default only the `.mdx` extension is supported.
extension: /\.mdx?$/,
options: {/* otherOptions… */}
})
const nextConfig = withMdx({
// Support MDX files as pages:
pageExtensions: ['md', 'mdx', 'tsx', 'ts', 'jsx', 'js'],
})
export default nextConfig
(alias) function nextMdx(options?: nextMdx.NextMDXOptions): WithMDX
(alias) namespace nextMdx
import nextMdxconst withMdx: WithMDX(property) nextMDX.NextMDXOptions.extension?: RuleSetConditionAbsoluteA webpack rule test to match files to treat as MDX.
- @default /.mdx$/
- @example // Support both .md and .mdx files. /.mdx?$/
(property) nextMDX.NextMDXOptions.options?: Options & {
remarkPlugins?: (string | [name: string, options: any] | NonNullable<Options["remarkPlugins"]>[number])[] | Options["remarkPlugins"];
rehypePlugins?: (string | [name: string, options: any] | NonNullable<Options["rehypePlugins"]>[number])[] | Options["rehypePlugins"];
}The options to pass to MDX.
const nextConfig: NextConfigconst withMdx: (config: NextConfig) => NextConfig(property) pageExtensions: string[]const nextConfig: NextConfigNext.js has its own MDX integration. Install and configure @next/mdx.
Do not use providerImportSource and @mdx-js/react with Next to inject components. Add an mdx-components.tsx (in src/ or /) file instead. See Configuring MDX on nextjs.org for more info.
Parcel
Parcel has its own plugin to support MDX. See @parcel/transformer-mdx on how to use MDX with Parcel.
Note: the official Parcel plugin is currently not maintained. For a maintained alternative, try parcel-transformer-mdx.
JSX runtimes
Emotion
Expand example
import {compile} from '@mdx-js/mdx'
const js = String(await compile('# hi', {jsxImportSource: '@emotion/react', /* otherOptions… */}))
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
const js: stringvar String: StringConstructor
(value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
(property) jsxImportSource?: string | null | undefinedPlace to import automatic JSX runtimes from (default: 'react'); when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs.
Emotion is supported when jsxImportSource in ProcessorOptions is set to '@emotion/react'. You can optionally install and configure @mdx-js/react to support context based component passing.
See also ¶ React, which is used in Emotion, and see ¶ Rollup and ¶ webpack, which you might be using, for more info.
Ink
Expand example
# Hi!
import React from 'react'
import {Text, render} from 'ink'
import Content from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
render(
React.createElement(Content, {
components: {
h1(properties) {
return React.createElement(Text, {bold: true, ...properties})
},
p: Text
}
})
)
(alias) namespace React
import React(alias) function Text({ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, "aria-label": ariaLabel, "aria-hidden": ariaHidden, }: Props): React.JSX.Element | null
import TextThis component can display text, and change its style to make it colorful, bold, underline, italic or strikethrough.
(alias) const render: (node: React.ReactNode, options?: NodeJS.WriteStream | RenderOptions) => Instance
import renderMount a component and render the output.
(alias) function Content(props: MDXProps): Element
import ContentAn function component which renders the MDX content using JSX.
- @param props This value is be available as the named variable
propsinside the MDX component. - @returns A JSX element. The meaning of this may depend on the project configuration. I.e. it could be a React, Preact, or Vuex element.
(alias) render(node: React.ReactNode, options?: NodeJS.WriteStream | RenderOptions): Instance
import renderMount a component and render the output.
(alias) namespace React
import Reactfunction React.createElement<MDXProps>(type: React.FunctionComponent<MDXProps>, props?: (React.Attributes & MDXProps) | null | undefined, ...children: React.ReactNode[]): React.FunctionComponentElement<MDXProps> (+6 overloads)(alias) function Content(props: MDXProps): Element
import ContentAn function component which renders the MDX content using JSX.
- @param props This value is be available as the named variable
propsinside the MDX component. - @returns A JSX element. The meaning of this may depend on the project configuration. I.e. it could be a React, Preact, or Vuex element.
(property) MDXProps.components?: MDXComponentsThis prop may be used to customize how certain components are rendered.
(method) h1(properties: JSX.IntrinsicElements): React.FunctionComponentElement<Props>(parameter) properties: JSX.IntrinsicElements(alias) namespace React
import Reactfunction React.createElement<Props>(type: React.FunctionComponent<Props>, props?: (React.Attributes & Props) | null | undefined, ...children: React.ReactNode[]): React.FunctionComponentElement<Props> (+6 overloads)(alias) function Text({ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, "aria-label": ariaLabel, "aria-hidden": ariaHidden, }: Props): React.JSX.Element | null
import TextThis component can display text, and change its style to make it colorful, bold, underline, italic or strikethrough.
(property) bold?: booleanMake the text bold.
(parameter) properties: JSX.IntrinsicElements(property) p: ({ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, "aria-label": ariaLabel, "aria-hidden": ariaHidden, }: Props) => React.JSX.Element | null(alias) function Text({ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, "aria-label": ariaLabel, "aria-hidden": ariaHidden, }: Props): React.JSX.Element | null
import TextThis component can display text, and change its style to make it colorful, bold, underline, italic or strikethrough.
Can be used with:
node --loader=@mdx-js/node-loader example.js
Ink uses the React JSX runtime, so set that up. You will need to swap HTML elements out for Ink’s components. See § Table of components for what those are and Ink’s docs on what they can be replaced with.
See also ¶ Node.js and ¶ React for more info.
Preact
Expand example
import {compile} from '@mdx-js/mdx'
const js = String(await compile('# hi', {jsxImportSource: 'preact', /* otherOptions… */}))
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
const js: stringvar String: StringConstructor
(value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
(property) jsxImportSource?: string | null | undefinedPlace to import automatic JSX runtimes from (default: 'react'); when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs.
Preact is supported when jsxImportSource in ProcessorOptions is set to 'preact'. You can optionally install and configure @mdx-js/preact to support context based component passing.
See also ¶ Rollup, ¶ esbuild, and ¶ webpack, which you might be using, for more info.
React
React is supported by default. You can optionally install and configure @mdx-js/react to support context based component passing.
See also ¶ Rollup, ¶ esbuild, and ¶ webpack, which you might be using, for more info.
Theme UI
Theme UI has its own plugin to support MDX. See @theme-ui/mdx on how to use MDX with Theme UI.
Svelte
Expand example
import {compile} from '@mdx-js/mdx'
const js = String(await compile('# hi', {jsxImportSource: 'svelte-jsx', /* otherOptions… */}))
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
const js: stringvar String: StringConstructor
(value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
(property) jsxImportSource?: string | null | undefinedPlace to import automatic JSX runtimes from (default: 'react'); when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs.
Svelte is supported when jsxImportSource in ProcessorOptions is set to 'svelte-jsx'.
See also ¶ Rollup, ¶ esbuild, and ¶ webpack, which you might be using, for more info.
Vue
Expand example
import {compile} from '@mdx-js/mdx'
const js = String(await compile('# hi', {jsxImportSource: 'vue', /* otherOptions… */}))
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
const js: stringvar String: StringConstructor
(value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
(property) jsxImportSource?: string | null | undefinedPlace to import automatic JSX runtimes from (default: 'react'); when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs.
Vue is supported when jsxImportSource in ProcessorOptions is set to 'vue'. You can optionally install and configure @mdx-js/vue to support context based component passing.
See also ¶ Vite, which you might be using, for more info.
Solid
Expand example
import {compile} from '@mdx-js/mdx'
const js = String(await compile('# hi', {jsxImportSource: 'solid-js/h', /* otherOptions… */}))
(alias) function compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
const js: stringvar String: StringConstructor
(value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings.
(alias) compile(vfileCompatible: Readonly<Compatible>, compileOptions?: Readonly<CompileOptions> | null | undefined): Promise<VFile>
import compileCompile MDX to JS.
- @param vfileCompatible MDX document to parse.
- @param compileOptions Compile configuration (optional).
- @return Promise to compiled file.
(property) jsxImportSource?: string | null | undefinedPlace to import automatic JSX runtimes from (default: 'react'); when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs.
Solid is supported when jsxImportSource in ProcessorOptions is set to 'solid-js/h'.
See also ¶ Rollup and ¶ Vite, which you might be using, for more info.
JavaScript engines
Node.js
MDX files can be imported in Node by using @mdx-js/node-loader. See its readme on how to configure it.
Bun
MDX files can be imported in Bun by using Create an esbuild plugin to compile MDX to JS. esbuild takes care of turning modern JavaScript features into syntax that works wherever you want it to. With other integrations you might need to use Babel for this, but with esbuild that’s not needed. See esbuild’s docs for more info. A Bun plugin. Used for extending Bun's behavior at runtime, or with {@link Bun.build } Create an esbuild plugin to compile MDX to JS. esbuild takes care of turning modern JavaScript features into syntax that works wherever you want it to. With other integrations you might need to use Babel for this, but with esbuild that’s not needed. See esbuild’s docs for more info. A Bun plugin. Used for extending Bun's behavior at runtime, or with {@link Bun.build }@mdx-js/esbuild.Expand example
preload = ["./bun-mdx.ts"]
import mdx from '@mdx-js/esbuild'
import {type BunPlugin, plugin} from 'bun'
await plugin(mdx() as unknown as BunPlugin)
(alias) function mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdx(alias) interface BunPlugin
import BunPlugin(alias) const plugin: Bun.BunRegisterPlugin
import plugin(alias) plugin<BunPlugin>(options: BunPlugin): void | Promise<void>
import plugin(alias) mdx(options?: Readonly<Options> | null | undefined): Plugin
import mdx(alias) interface BunPlugin
import BunPlugin
Further reading
- If you want to use MDX content in your project, see § Using MDX
- If you’re getting errors integrating MDX, see § Troubleshooting MDX or § Support