Skip to content

Latest commit

 

History

History
384 lines (281 loc) · 13.6 KB

File metadata and controls

384 lines (281 loc) · 13.6 KB
type title description githubIntegrationURL category i18nReady
integration
@astrojs/mdx
Learn how to use the @astrojs/mdx integration in your Astro project.
other
true

import PackageManagerTabs from '/components/tabs/PackageManagerTabs.astro' import ReadMore from '/components/ReadMore.astro' import Since from '~/components/Since.astro'

This Astro integration enables the usage of MDX components and allows you to create pages as .mdx files.

Why MDX?

MDX allows you to use variables, JSX expressions and components within Markdown content in Astro. If you have existing content authored in MDX, this integration allows you to bring those files to your Astro project.

Installation

Astro includes an astro add command to automate the setup of official integrations. If you prefer, you can install integrations manually instead.

Run one of the following commands in a new terminal window.

```sh npx astro add mdx ``` ```sh pnpm astro add mdx ``` ```sh yarn astro add mdx ```

If you run into any issues, feel free to report them to us on GitHub and try the manual installation steps below.

Manual Install

First, install the @astrojs/mdx package:

```sh npm install @astrojs/mdx ``` ```sh pnpm add @astrojs/mdx ``` ```sh yarn add @astrojs/mdx ```

Then, apply the integration to your astro.config.* file using the integrations property:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  // ...
  integrations: [mdx()],
});

Editor Integration

For editor support in VS Code, install the official MDX extension.

For other editors, use the MDX language server.

Usage

Visit the MDX docs to learn about using standard MDX features.

MDX in Astro

Adding the MDX integration enhances your Markdown authoring with JSX variables, expressions and components.

It also adds extra features to standard MDX, including support for Markdown-style frontmatter in MDX. This allows you to use most of Astro's built-in Markdown features.

.mdx files must be written in MDX syntax rather than Astro’s HTML-like syntax.

Using Exported Variables in MDX

MDX supports using export statements to add variables to your MDX content or to export data to a component that imports it.

For example, you can export a title field from an MDX page or component to use as a heading with {JSX expressions}:

export const title = 'My first MDX post'

# {title}

Or you can use that exported title in your page using import and import.meta.glob() statements:

---
const matches = await import.meta.glob('./posts/*.mdx', { eager: true });
const posts = Object.values(posts);
---

{posts.map(post => <p>{post.title}</p>)}

Exported Properties

The following properties are available to a .astro component when using an import statement or import.meta.glob():

  • file - The absolute file path (e.g. /home/user/projects/.../file.mdx).
  • url - The URL of the page (e.g. /en/guides/markdown-content).
  • frontmatter - Contains any data specified in the file’s YAML frontmatter.
  • getHeadings() - An async function that returns an array of all headings (<h1> to <h6>) in the file with the type: { depth: number; slug: string; text: string }[]. Each heading’s slug corresponds to the generated ID for a given heading and can be used for anchor links.
  • <Content /> - A component that returns the full, rendered contents of the file.
  • (any export value) - MDX files can also export data with an export statement.

Using Frontmatter Variables in MDX

The Astro MDX integration includes support for using frontmatter in MDX by default. Add frontmatter properties just as you would in Markdown files, and these variables are available to use in the template, and as named properties when importing the file somewhere else.

---
layout: '../../layouts/BlogPostLayout.astro'
title: 'My first MDX post'
---

# {frontmatter.title}

Using Components in MDX

After installing the MDX integration, you can import and use both Astro components and UI framework components in MDX (.mdx) files just as you would use them in any other Astro component.

Don't forget to include a client:directive on your UI framework components, if necessary!

See more examples of using import and export statements in the MDX docs.

---
layout: ../layouts/BaseLayout.astro
title: About me
---
import Button from '../components/Button.astro';
import ReactCounter from '../components/ReactCounter.jsx';

I live on **Mars** but feel free to <Button title="Contact me" />.

Here is my counter component, working in MDX:

<ReactCounter client:load />

Custom components with imported MDX

When rendering imported MDX content, custom components can be passed via the components prop.

---
import { Content, components } from '../content.mdx';
import Heading from '../Heading.astro';
---
<!-- Creates a custom <h1> for the # syntax, _and_ applies any custom components defined in `content.mdx` -->
<Content components={{...components, h1: Heading }} />

:::note Custom components defined and exported in an MDX file must be imported and then passed back to the <Content /> component via the components property. :::

Assigning Custom Components to HTML elements

With MDX, you can map Markdown syntax to custom components instead of their standard HTML elements. This allows you to write in standard Markdown syntax, but apply special component styling to selected elements.

Import your custom component into your .mdx file, then export a components object that maps the standard HTML element to your custom component:

import Blockquote from '../components/Blockquote.astro';
export const components = {blockquote: Blockquote}

> This quote will be a custom Blockquote
---
const props = Astro.props;
---
<blockquote {...props} class="bg-blue-50 p-4">
  <span class="text-4xl text-blue-600 mb-2">“</span>
  <slot /> <!-- Be sure to add a `<slot/>` for child content! -->
</blockquote>

Visit the MDX website for a full list of HTML elements that can be overwritten as custom components.

Configuration

Once the MDX integration is installed, no configuration is necessary to use .mdx files in your Astro project.

You can configure how your MDX is rendered with the following options:

Options inherited from Markdown config

All markdown configuration options can be configured separately in the MDX integration. This includes remark and rehype plugins, syntax highlighting, and more. Options will default to those in your Markdown config (see the extendMarkdownConfig option to modify this).

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import remarkToc from 'remark-toc';
import rehypePresetMinify from 'rehype-preset-minify';

export default defineConfig({
  // ...
  integrations: [
    mdx({
      syntaxHighlight: 'shiki',
      shikiConfig: { theme: 'dracula' },
      remarkPlugins: [remarkToc],
      rehypePlugins: [rehypePresetMinify],
      remarkRehype: { footnoteLabel: 'Footnotes' },
      gfm: false,
    }),
  ],
});

:::caution MDX does not support passing remark and rehype plugins as a string. You should install, import, and apply the plugin function instead. :::

See the Markdown Options reference for a complete list of options.

extendMarkdownConfig

  • Type: boolean
  • Default: true

MDX will extend your project's existing Markdown configuration by default. To override individual options, you can specify their equivalent in your MDX configuration.

For example, say you need to disable GitHub-Flavored Markdown and apply a different set of remark plugins for MDX files. You can apply these options like so, with extendMarkdownConfig enabled by default:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  // ...
  markdown: {
    syntaxHighlight: 'prism',
    remarkPlugins: [remarkPlugin1],
    gfm: true,
  },
  integrations: [
    mdx({
      // `syntaxHighlight` inherited from Markdown

      // Markdown `remarkPlugins` ignored,
      // only `remarkPlugin2` applied.
      remarkPlugins: [remarkPlugin2],
      // `gfm` overridden to `false`
      gfm: false,
    }),
  ],
});

You may also need to disable markdown config extension in MDX. For this, set extendMarkdownConfig to false:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  // ...
  markdown: {
    remarkPlugins: [remarkPlugin1],
  },
  integrations: [
    mdx({
      // Markdown config now ignored
      extendMarkdownConfig: false,
      // No `remarkPlugins` applied
    }),
  ],
});

recmaPlugins

These are plugins that modify the output estree directly. This is useful for modifying or injecting JavaScript variables in your MDX files.

We suggest using AST Explorer to play with estree outputs, and trying estree-util-visit for searching across JavaScript nodes.

optimize

  • Type: boolean | { ignoreElementNames?: string[] }

This is an optional configuration setting to optimize the MDX output for faster builds and rendering via an internal rehype plugin. This may be useful if you have many MDX files and notice slow builds. However, this option may generate some unescaped HTML, so make sure your site's interactive parts still work correctly after enabling it.

This is disabled by default. To enable MDX optimization, add the following to your MDX integration configuration:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  // ...
  integrations: [
    mdx({
      optimize: true,
    }),
  ],
});

ignoreElementNames

  • Type: string[]

Previously known as `customComponentNames`.

An optional property of optimize to prevent the MDX optimizer from handling certain element names, like custom components passed to imported MDX content via the components prop.

You will need to exclude these components from optimization as the optimizer eagerly converts content into a static string, which will break custom components that needs to be dynamically rendered.

For example, the intended MDX output of the following is <Heading>...</Heading> in place of every "<h1>...</h1>":

---
import { Content, components } from '../content.mdx';
import Heading from '../Heading.astro';
---

<Content components={{ ...components, h1: Heading }} />

To configure optimization for this using the ignoreElementNames property, specify an array of HTML element names that should be treated as custom components:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  // ...
  integrations: [
    mdx({
      optimize: {
        // Prevent the optimizer from handling `h1` elements
        ignoreElementNames: ['h1'],
      },
    }),
  ],
});

Note that if your MDX file configures custom components using export const components = { ... }, then you do not need to manually configure this option. The optimizer will automatically detect them.

Examples