Full Code of mdx-js/mdx for AI

main 579f20e1943b cached
167 files
689.2 KB
191.2k tokens
152 symbols
1 requests
Download .txt
Showing preview only (733K chars total). Download the full file or copy to clipboard to get everything.
Repository: mdx-js/mdx
Branch: main
Commit: 579f20e1943b
Files: 167
Total size: 689.2 KB

Directory structure:
gitextract_mjw34tia/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── bb.yml
│       ├── main.yml
│       └── website.yml
├── .gitignore
├── .prettierignore
├── .vercelignore
├── changelog.md
├── docs/
│   ├── .remarkrc.js
│   ├── 404.mdx
│   ├── _asset/
│   │   ├── editor.jsx
│   │   ├── index.css
│   │   └── index.js
│   ├── _component/
│   │   ├── blog.jsx
│   │   ├── foot-site.jsx
│   │   ├── home.jsx
│   │   ├── icon/
│   │   │   ├── github.jsx
│   │   │   ├── mdx.jsx
│   │   │   └── open-collective.jsx
│   │   ├── layout.jsx
│   │   ├── nav-site.jsx
│   │   ├── nav.jsx
│   │   ├── note.jsx
│   │   ├── snowfall.jsx
│   │   └── sort.js
│   ├── _config.js
│   ├── blog/
│   │   ├── conf.mdx
│   │   ├── custom-pragma.mdx
│   │   ├── index.mdx
│   │   ├── shortcodes.mdx
│   │   ├── v1.mdx
│   │   ├── v2.mdx
│   │   └── v3.mdx
│   ├── community/
│   │   ├── about.mdx
│   │   ├── contribute.mdx
│   │   ├── index.mdx
│   │   ├── projects.mdx
│   │   ├── sponsor.mdx
│   │   └── support.mdx
│   ├── docs/
│   │   ├── extending-mdx.mdx
│   │   ├── getting-started.mdx
│   │   ├── index.mdx
│   │   ├── troubleshooting-mdx.mdx
│   │   ├── using-mdx.mdx
│   │   └── what-is-mdx.mdx
│   ├── guides/
│   │   ├── embed.mdx
│   │   ├── frontmatter.mdx
│   │   ├── gfm.mdx
│   │   ├── index.mdx
│   │   ├── injecting-components.mdx
│   │   ├── math.mdx
│   │   ├── mdx-on-demand.mdx
│   │   └── syntax-highlighting.mdx
│   ├── index.mdx
│   ├── migrating/
│   │   ├── v1.mdx
│   │   ├── v2.mdx
│   │   └── v3.mdx
│   ├── packages/
│   │   └── index.mdx
│   ├── playground.mdx
│   └── table-of-components.mdx
├── license
├── package.json
├── packages/
│   ├── esbuild/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── loader/
│   │   ├── index.cjs
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── mdx/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   ├── compile.js
│   │   │   ├── core.js
│   │   │   ├── evaluate.js
│   │   │   ├── node-types.js
│   │   │   ├── plugin/
│   │   │   │   ├── recma-build-jsx-transform.js
│   │   │   │   ├── recma-document.js
│   │   │   │   ├── recma-jsx-rewrite.js
│   │   │   │   ├── rehype-remove-raw.js
│   │   │   │   └── remark-mark-and-unravel.js
│   │   │   ├── run.js
│   │   │   ├── types.d.ts
│   │   │   └── util/
│   │   │       ├── create-format-aware-processors.js
│   │   │       ├── estree-util-create.js
│   │   │       ├── estree-util-declaration-to-expression.js
│   │   │       ├── estree-util-is-declaration.js
│   │   │       ├── estree-util-specifiers-to-declarations.js
│   │   │       ├── estree-util-to-binary-addition.js
│   │   │       ├── estree-util-to-id-or-member-expression.js
│   │   │       ├── extnames-to-regex.js
│   │   │       ├── extnames.js
│   │   │       ├── resolve-evaluate-options.js
│   │   │       └── resolve-file-and-options.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   ├── compile.js
│   │   │   ├── context/
│   │   │   │   ├── components.js
│   │   │   │   ├── data.js
│   │   │   │   └── run.js
│   │   │   ├── core.js
│   │   │   ├── evaluate.js
│   │   │   ├── index.js
│   │   │   └── syntax.js
│   │   └── tsconfig.json
│   ├── node-loader/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   ├── condition.default.js
│   │   │   ├── condition.development.js
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── preact/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.jsx
│   │   └── tsconfig.json
│   ├── react/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.jsx
│   │   └── tsconfig.json
│   ├── remark-mdx/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── rollup/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   ├── index.js
│   │   │   └── vite-entry.mdx
│   │   └── tsconfig.json
│   └── vue/
│       ├── index.js
│       ├── lib/
│       │   └── index.js
│       ├── license
│       ├── package.json
│       ├── readme.md
│       ├── test/
│       │   └── index.js
│       └── tsconfig.json
├── readme.md
├── renovate.json5
├── script/
│   └── jsx-loader.js
├── tsconfig.json
├── vercel.json
└── website/
    ├── generate.js
    ├── mdx-loader.js
    ├── post.js
    ├── prep.js
    ├── schema-description.js
    └── types.d.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true


================================================
FILE: .github/workflows/bb.yml
================================================
jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - uses: unifiedjs/beep-boop-beta@main
        with:
          repo-token: ${{secrets.GITHUB_TOKEN}}
name: bb
on:
  issues:
    types: [closed, edited, labeled, opened, reopened, unlabeled]
  pull_request_target:
    types: [closed, edited, labeled, opened, reopened, unlabeled]


================================================
FILE: .github/workflows/main.yml
================================================
jobs:
  small:
    env:
      PUPPETEER_SKIP_DOWNLOAD: 1
    name: test / ${{matrix.os}} / ${{matrix.node}}
    runs-on: ${{matrix.os}}
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          cache: npm
          node-version: ${{matrix.node}}
      - run: npm ci
      - run: npm run test-api
    strategy:
      matrix:
        include:
          - node: lts/iron
            os: ubuntu-latest
        node:
          - lts/*
        os:
          - macos-latest
          - windows-latest
  full:
    env:
      PUPPETEER_SKIP_DOWNLOAD: 1
    name: full build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          cache: npm
          node-version: lts/*
      - run: npm ci
      - run: npm test
      - uses: codecov/codecov-action@v5
name: main
on:
  - pull_request
  - push


================================================
FILE: .github/workflows/website.yml
================================================
jobs:
  deploy:
    environment:
      name: Website
      url: ${{steps.deployment.outputs.page_url}}
    permissions:
      contents: read
      id-token: write
      pages: write
    # To do: replace w/ `ubuntu-latest` when upstream is solved:
    # <https://github.com/puppeteer/puppeteer/issues/12818>.
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
      - run: npm ci
      - run: npm run docs
      - uses: actions/upload-pages-artifact@v4
        with:
          path: public
      - uses: actions/deploy-pages@v4
        id: deployment
name: website
on:
  push:
    branches:
      - main


================================================
FILE: .gitignore
================================================
.DS_Store
coverage/
node_modules/
*.d.cts
*.d.ts
*.map
*.tsbuildinfo
/public/
!/packages/mdx/lib/types.d.ts
!/website/types.d.ts


================================================
FILE: .prettierignore
================================================
node_modules/
coverage/
public/
*.md
*.mdx


================================================
FILE: .vercelignore
================================================
node_modules/


================================================
FILE: changelog.md
================================================
# Changelog

See [GitHub Releases][releases] for the changelog.

[releases]: https://github.com/mdx-js/mdx/releases


================================================
FILE: docs/.remarkrc.js
================================================
/**
 * @import {CheckFlag} from 'remark-lint-fenced-code-flag'
 * @import {Preset} from 'unified'
 */

import remarkPresetWooorm from 'remark-preset-wooorm'
import remarkLintFencedCodeFlag, {
  checkGithubLinguistFlag
} from 'remark-lint-fenced-code-flag'
import remarkLintNoHtml from 'remark-lint-no-html'
import remarkValidateLinks from 'remark-validate-links'

/** @type {Preset} */
const remarkPresetMdx = {
  plugins: [
    remarkPresetWooorm,
    [remarkLintFencedCodeFlag, check],
    [remarkLintNoHtml, false],
    [remarkValidateLinks, false]
  ]
}

export default remarkPresetMdx

/**
 * Check according to GitHub Linguist.
 *
 * @param {string} value
 *   Language flag to check.
 * @returns {string | undefined}
 *   Whether the flag is valid (`undefined`),
 *   or a message to warn about (`string`).
 * @satisfies {CheckFlag}
 */
function check(value) {
  // To do: investigate if we can change ` ```jsx ` -> ` ```js `?
  if (value === 'jsx' || value === 'mdx-invalid') return undefined
  return checkGithubLinguistFlag(value)
}


================================================
FILE: docs/404.mdx
================================================
import {Note} from './_component/note.jsx'

export {Home as default} from './_component/home.jsx'
export const navExclude = true

# 404: Not found

Aww, snap.
Unfortunately this page doesn’t exist.
Perhaps you can find what you’re looking for [on GitHub][search]?

<Note type="info">
  **Note**: Did you come here from a website linking to it?
  Pretty sure this page used to exist?
  Please [open an issue](https://github.com/mdx-js/mdx/issues/new) to let us
  know so we can fix it!
</Note>

[search]: https://github.com/mdx-js/mdx/search


================================================
FILE: docs/_asset/editor.jsx
================================================
/* @jsxRuntime automatic */
/* @jsxImportSource react */

/* eslint-disable unicorn/prefer-global-this */

/**
 * @import {Grammar} from '@wooorm/starry-night'
 * @import {Node as EstreeNode, Program} from 'estree'
 * @import {Nodes as HastNodes, Root as HastRoot} from 'hast'
 * @import {Nodes as MdastNodes, Root as MdastRoot} from 'mdast'
 * @import {
    MdxJsxAttribute,
    MdxJsxAttributeValueExpression,
    MdxJsxExpressionAttribute
 * } from 'mdast-util-mdx-jsx'
 * @import {MDXModule} from 'mdx/types.js'
 * @import {ReactNode} from 'react'
 * @import {FallbackProps} from 'react-error-boundary'
 * @import {PluggableList} from 'unified'
 * @import {Node as UnistNode} from 'unist'
 */

/**
 * @typedef DisplayProperties
 *   Properties.
 * @property {Error} error
 *   Error.
 *
 * @typedef EvalNok
 *   Not OK.
 * @property {false} ok
 *   Whether OK.
 * @property {Error} value
 *   Error.
 *
 * @typedef EvalOk
 *   OK.
 * @property {true} ok
 *   Whether OK.
 * @property {ReactNode} value
 *   Result.
 *
 * @typedef {EvalNok | EvalOk} EvalResult
 *   Result.
 */

import {compile, nodeTypes, run} from '@mdx-js/mdx'
import {createStarryNight} from '@wooorm/starry-night'
import sourceCss from '@wooorm/starry-night/source.css'
import sourceJs from '@wooorm/starry-night/source.js'
import sourceJson from '@wooorm/starry-night/source.json'
import sourceMdx from '@wooorm/starry-night/source.mdx'
import sourceTs from '@wooorm/starry-night/source.ts'
import sourceTsx from '@wooorm/starry-night/source.tsx'
import textHtmlBasic from '@wooorm/starry-night/text.html.basic'
import textMd from '@wooorm/starry-night/text.md'
import {visit as visitEstree} from 'estree-util-visit'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {useEffect, useState} from 'react'
import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
import ReactDom from 'react-dom/client'
import {ErrorBoundary} from 'react-error-boundary'
import rehypeRaw from 'rehype-raw'
import remarkDirective from 'remark-directive'
import remarkFrontmatter from 'remark-frontmatter'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import {removePosition} from 'unist-util-remove-position'
import {visit} from 'unist-util-visit'
import {VFile} from 'vfile'

const sample = `# Hello, world!

Below is an example of markdown in JSX.

<div style={{backgroundColor: 'violet', padding: '1rem'}}>
  Try and change the background color to \`tomato\`.
</div>`

/** @type {ReadonlyArray<Grammar>} */
const grammars = [
  sourceCss,
  sourceJs,
  sourceJson,
  sourceMdx,
  sourceTs,
  sourceTsx,
  textHtmlBasic,
  textMd
]

/** @type {Awaited<ReturnType<typeof createStarryNight>>} */
let starryNight

const editor = document.querySelector('#js-editor')

if (window.location.pathname === '/playground/' && editor) {
  const root = document.createElement('div')
  root.classList.add('playground')
  editor.after(root)
  init(root)
}

/**
 * @param {Element} main
 *   DOM element.
 * @returns {undefined}
 *   Nothing.
 */
function init(main) {
  const root = ReactDom.createRoot(main)

  createStarryNight(grammars).then(
    /**
     * @returns {undefined}
     *   Nothing.
     */
    function (x) {
      starryNight = x

      const missing = starryNight.missingScopes()
      if (missing.length > 0) {
        throw new Error('Unexpected missing required scopes: `' + missing + '`')
      }

      root.render(<Playground />)
    }
  )
}

function Playground() {
  const [directive, setDirective] = useState(false)
  const [evalResult, setEvalResult] = useState(
    // Cast to more easily use actual value.
    /** @type {unknown} */ (undefined)
  )
  const [development, setDevelopment] = useState(false)
  const [frontmatter, setFrontmatter] = useState(false)
  const [gfm, setGfm] = useState(false)
  const [formatMarkdown, setFormatMarkdown] = useState(false)
  const [generateJsx, setGenerateJsx] = useState(false)
  const [math, setMath] = useState(false)
  const [outputFormatFunctionBody, setOutputFormatFunctionBody] =
    useState(false)
  const [positions, setPositions] = useState(false)
  const [raw, setRaw] = useState(false)
  const [show, setShow] = useState('result')
  const [value, setValue] = useState(sample)

  useEffect(
    function () {
      go().then(
        function (ok) {
          setEvalResult({ok: true, value: ok})
        },
        /**
         * @param {Error} error
         *   Error.
         * @returns {undefined}
         *   Nothing.
         */
        function (error) {
          setEvalResult({ok: false, value: error})
        }
      )

      async function go() {
        /** @type {PluggableList} */
        const recmaPlugins = []
        /** @type {PluggableList} */
        const rehypePlugins = []
        /** @type {PluggableList} */
        const remarkPlugins = []

        if (directive) remarkPlugins.unshift(remarkDirective)
        if (frontmatter) remarkPlugins.unshift(remarkFrontmatter)
        if (gfm) remarkPlugins.unshift(remarkGfm)
        if (math) remarkPlugins.unshift(remarkMath)
        if (raw) rehypePlugins.unshift([rehypeRaw, {passThrough: nodeTypes}])

        const file = new VFile({
          basename: formatMarkdown ? 'example.md' : 'example.mdx',
          value
        })

        if (show === 'esast') recmaPlugins.push([captureEsast])
        if (show === 'hast') rehypePlugins.push([captureHast])
        if (show === 'mdast') remarkPlugins.push([captureMdast])
        /** @type {UnistNode | undefined} */
        let ast

        await compile(file, {
          development: show === 'result' ? false : development,
          jsx: show === 'code' || show === 'esast' ? generateJsx : false,
          outputFormat:
            show === 'result' || outputFormatFunctionBody
              ? 'function-body'
              : 'program',
          recmaPlugins,
          rehypePlugins,
          remarkPlugins
        })

        if (show === 'result') {
          /** @type {MDXModule} */
          const result = await run(String(file), {
            Fragment,
            jsx,
            jsxs,
            baseUrl: window.location.href
          })

          return (
            <ErrorBoundary
              FallbackComponent={ErrorFallback}
              resetKeys={[value]}
            >
              <div className="playground-result">{result.default({})}</div>
            </ErrorBoundary>
          )
        }

        if (ast) {
          return (
            <pre>
              <code>
                {toJsxRuntime(
                  starryNight.highlight(
                    JSON.stringify(ast, undefined, 2),
                    'source.json'
                  ),
                  {Fragment, jsx, jsxs}
                )}
              </code>
            </pre>
          )
        }

        // `show === 'code'`
        return (
          <pre>
            <code>
              {toJsxRuntime(starryNight.highlight(String(file), 'source.js'), {
                Fragment,
                jsx,
                jsxs
              })}
            </code>
          </pre>
        )

        function captureMdast() {
          /**
           * @param {MdastRoot} tree
           *   Tree.
           * @returns {undefined}
           *   Nothing.
           */
          return function (tree) {
            const clone = structuredClone(tree)
            if (!positions) cleanUnistTree(clone)
            ast = clone
          }
        }

        function captureHast() {
          /**
           * @param {HastRoot} tree
           *   Tree.
           * @returns {undefined}
           *   Nothing.
           */
          return function (tree) {
            const clone = structuredClone(tree)
            if (!positions) cleanUnistTree(clone)
            ast = clone
          }
        }

        function captureEsast() {
          /**
           * @param {Program} tree
           *   Tree.
           * @returns {undefined}
           *   Nothing.
           */
          return function (tree) {
            const clone = structuredClone(tree)
            if (!positions) visitEstree(clone, removeFromEstree)
            ast = clone
          }
        }
      }
    },
    [
      development,
      directive,
      frontmatter,
      gfm,
      generateJsx,
      formatMarkdown,
      math,
      outputFormatFunctionBody,
      positions,
      raw,
      show,
      value
    ]
  )

  const scope = formatMarkdown ? 'text.md' : 'source.mdx'
  // Cast to actual value.
  const compiledResult = /** @type {EvalResult | undefined} */ (evalResult)
  /** @type {ReactNode | undefined} */
  let display

  if (compiledResult) {
    if (compiledResult.ok) {
      display = compiledResult.value
    } else {
      display = (
        <div>
          <p>Could not compile code:</p>
          <DisplayError error={compiledResult.value} />
        </div>
      )
    }
  }

  return (
    <>
      <form>
        <div className="playground-area">
          <div className="playground-inner">
            <div className="playground-draw">
              {toJsxRuntime(starryNight.highlight(value, scope), {
                Fragment,
                jsx,
                jsxs
              })}
              {/* Trailing whitespace in a `textarea` is shown, but not in a `div`
          with `white-space: pre-wrap`.
          Add a `br` to make the last newline explicit. */}
              {/\n[ \t]*$/.test(value) ? <br /> : undefined}
            </div>
            <textarea
              spellCheck="false"
              className="playground-write"
              value={value}
              rows={value.split('\n').length + 1}
              onChange={function (event) {
                setValue(event.target.value)
              }}
            />
          </div>
        </div>
        <div className="playground-controls">
          <fieldset>
            <legend>Show</legend>
            <label>
              <select
                name="show"
                onChange={function (event) {
                  setShow(event.target.value)
                }}
              >
                <option value="result">evaluated result</option>
                <option value="code">compiled code</option>
                <option value="mdast">mdast (markdown)</option>
                <option value="hast">hast (html)</option>
                <option value="esast">esast (javascript)</option>
              </select>{' '}
            </label>
          </fieldset>
          <fieldset>
            <legend>Plugin</legend>
            <label>
              <input
                type="checkbox"
                name="directive"
                checked={directive}
                onChange={function () {
                  setDirective(!directive)
                }}
              />{' '}
              use{' '}
              <a href="https://github.com/remarkjs/remark-directive">
                <code>remark-directive</code>
              </a>
            </label>
            <label>
              <input
                type="checkbox"
                name="frontmatter"
                checked={frontmatter}
                onChange={function () {
                  setFrontmatter(!frontmatter)
                }}
              />{' '}
              use{' '}
              <a href="https://github.com/remarkjs/remark-frontmatter">
                <code>remark-frontmatter</code>
              </a>
            </label>
            <label>
              <input
                type="checkbox"
                name="gfm"
                checked={gfm}
                onChange={function () {
                  setGfm(!gfm)
                }}
              />{' '}
              use{' '}
              <a href="https://github.com/remarkjs/remark-gfm">
                <code>remark-gfm</code>
              </a>
            </label>
            <label>
              <input
                type="checkbox"
                name="math"
                checked={math}
                onChange={function () {
                  setMath(!math)
                }}
              />{' '}
              use{' '}
              <a href="https://github.com/remarkjs/remark-math">
                <code>remark-math</code>
              </a>
            </label>
            <label>
              <input
                type="checkbox"
                name="raw"
                checked={raw}
                onChange={function () {
                  setRaw(!raw)
                }}
              />{' '}
              use{' '}
              <a href="https://github.com/rehypejs/rehype-raw">
                <code>rehype-raw</code>
              </a>
            </label>
          </fieldset>
          <fieldset>
            <legend>Input format</legend>
            <label>
              <input
                type="radio"
                name="language"
                checked={!formatMarkdown}
                onChange={function () {
                  setFormatMarkdown(false)
                }}
              />{' '}
              MDX (<code>format: &apos;mdx&apos;</code>)
            </label>
            <label>
              <input
                type="radio"
                name="language"
                checked={formatMarkdown}
                onChange={function () {
                  setFormatMarkdown(true)
                }}
              />{' '}
              markdown (<code>format: &apos;markdown&apos;</code>)
            </label>
          </fieldset>

          <fieldset disabled={show === 'result'}>
            <legend>Output format</legend>
            <label>
              <input
                type="radio"
                name="output-format"
                checked={outputFormatFunctionBody}
                onChange={function () {
                  setOutputFormatFunctionBody(true)
                }}
              />{' '}
              function body (
              <code>outputFormat: &apos;function-body&apos;</code>)
            </label>
            <label>
              <input
                type="radio"
                name="output-format"
                checked={!outputFormatFunctionBody}
                onChange={function () {
                  setOutputFormatFunctionBody(false)
                }}
              />{' '}
              program (<code>outputFormat: &apos;program&apos;</code>)
            </label>
          </fieldset>

          <fieldset disabled={show === 'result'}>
            <legend>Development</legend>
            <label>
              <input
                type="radio"
                name="development"
                checked={development}
                onChange={function () {
                  setDevelopment(true)
                }}
              />{' '}
              generate for development (<code>development: true</code>)
            </label>
            <label>
              <input
                type="radio"
                name="development"
                checked={!development}
                onChange={function () {
                  setDevelopment(false)
                }}
              />{' '}
              generate for production (<code>development: false</code>)
            </label>
          </fieldset>

          <fieldset disabled={show === 'result'}>
            <legend>JSX</legend>
            <label>
              <input
                type="radio"
                name="jsx"
                checked={generateJsx}
                onChange={function () {
                  setGenerateJsx(true)
                }}
              />{' '}
              keep JSX (<code>jsx: true</code>)
            </label>
            <label>
              <input
                type="radio"
                name="jsx"
                checked={!generateJsx}
                onChange={function () {
                  setGenerateJsx(false)
                }}
              />{' '}
              compile JSX away (<code>jsx: false</code>)
            </label>
          </fieldset>

          <fieldset disabled={show === 'result' || show === 'code'}>
            <legend>Tree</legend>
            <label>
              <input
                type="checkbox"
                name="positions"
                checked={positions}
                onChange={function () {
                  setPositions(!positions)
                }}
              />{' '}
              show <code>position</code> in tree
            </label>
          </fieldset>
        </div>
      </form>
      {display}
    </>
  )
}

/**
 *
 * @param {Readonly<FallbackProps>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
function ErrorFallback(properties) {
  // type-coverage:ignore-next-line
  const error = /** @type {Error} */ (properties.error)
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <DisplayError error={error} />
      <button type="button" onClick={properties.resetErrorBoundary}>
        Try again
      </button>
    </div>
  )
}

/**
 * @param {DisplayProperties} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
function DisplayError(properties) {
  return (
    <pre>
      <code>
        {String(
          properties.error.stack
            ? properties.error.message + '\n' + properties.error.stack
            : properties.error
        )}
      </code>
    </pre>
  )
}

/**
 * @param {HastRoot | MdastRoot} node
 *   mdast or hast root.
 * @returns {undefined}
 *   Nothing.
 */
function cleanUnistTree(node) {
  removePosition(node, {force: true})
  visit(node, cleanUnistNode)
}

/**
 * @param {HastNodes | MdastNodes | MdxJsxAttribute | MdxJsxAttributeValueExpression | MdxJsxExpressionAttribute} node
 *   Node.
 * @returns {undefined}
 *   Nothing.
 */
function cleanUnistNode(node) {
  if (
    node.type === 'mdxJsxAttribute' &&
    'value' in node &&
    node.value &&
    typeof node.value === 'object'
  ) {
    cleanUnistNode(node.value)
  }

  if (
    'attributes' in node &&
    node.attributes &&
    Array.isArray(node.attributes)
  ) {
    for (const attribute of node.attributes) {
      removePosition(attribute, {force: true})
      cleanUnistNode(attribute)
    }
  }

  if (node.data && 'estree' in node.data && node.data.estree) {
    visitEstree(node.data.estree, removeFromEstree)
  }
}

/**
 * @param {EstreeNode} node
 *   estree node.
 * @returns {undefined}
 *   Nothing.
 */
function removeFromEstree(node) {
  delete node.loc
  delete node.start
  delete node.end
  delete node.range
}


================================================
FILE: docs/_asset/index.css
================================================
:root {
  --sans:
    system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial,
    sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  --mono:
    'San Francisco Mono', 'Monaco', 'Consolas', 'Lucida Console',
    'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
  --white: #fff;
  --black: #1b1f24;
  --gray-0: #f6f8fa;
  --gray-1: #eaeef2;
  --gray-2: #d0d7de;
  --gray-3: #afb8c1;
  --gray-4: #8c959f;
  --gray-5: #6e7781;
  --gray-6: #57606a;
  --gray-7: #424a53;
  --gray-8: #32383f;
  --gray-9: #24292f;
  --blue-0: #ddf4ff;
  --blue-5: #0969da;
  --blue-9: #002155;
  --green-0: #dafbe1;
  --green-5: #1a7f37;
  --green-9: #002d11;
  --yellow-0: #fff8c5;
  --yellow-5: #9a6700;
  --yellow-9: #3b2300;
  --orange-0: #fff1e5;
  --orange-5: #bc4c00;
  --orange-9: #471700;
  --red-0: #ffebe9;
  --red-5: #cf222e;
  --red-9: #4c0014;
  --purple-0: #fbefff;
  --purple-5: #8250df;
  --purple-9: #2e1461;
  --pink-0: #ffeff7;
  --pink-5: #bf3989;
  --pink-9: #4d0336;
  --coral-0: #fff0eb;
  --coral-5: #c4432b;
  --coral-9: #510901;
  --mdx-yellow: hsl(39deg 97% 58%);
  --hl: var(--blue-5);
  --fg: var(--black);
  --bg: var(--white);

  /* We manually add a blur on `::before` of the container, so no background needed. */
  --docsearch-container-background: transparent !important;
  --docsearch-footer-background: var(--white) !important;
  --docsearch-footer-shadow: 0 -1px 0 0 var(--gray-2) !important;
  --docsearch-highlight-color: var(--hl) !important;
  --docsearch-hit-color: var(--gray-7) !important;
  --docsearch-hit-shadow: inset 0 0 0 1px var(--gray-2) !important;
  /* This is actually used in a `background` field so does not have to be a gradient. */
  --docsearch-key-gradient: var(--gray-0) !important;
  --docsearch-key-pressed-shadow: none !important;
  --docsearch-key-shadow: inset 0 -1px 0 var(--gray-4) !important;
  --docsearch-modal-background: var(--white) !important;
  /* Card shadow: <https://github.com/unifiedjs/unifiedjs.github.io/blob/4de0391/asset/index.css#L399> */
  --docsearch-modal-shadow:
    0 0 0 0.2em rgb(3 102 214 / 0%), 0 13px 27px -5px rgb(50 50 93 / 25%),
    0 8px 16px -8px rgb(0 0 0 / 30%), 0 -6px 16px -6px rgb(0 0 0 / 2.5%) !important;
  /* Use the regular color: */
  --docsearch-muted-color: var(--black) !important;
  --docsearch-primary-color: var(--hl) !important;
  --docsearch-searchbox-background: var(--white) !important;
  --docsearch-searchbox-focus-background: var(--gray-0) !important;
  --docsearch-searchbox-shadow: inset 0 0 0 2px var(--hl) !important;
  --docsearch-text-color: var(--black) !important;
}

* {
  box-sizing: border-box;
}

html {
  color-scheme: light dark;
  accent-color: var(--hl);
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  word-wrap: break-word;
  font-kerning: normal;
  font-family: var(--sans);
  font-feature-settings: 'kern', 'liga', 'clig', 'calt';
  line-height: calc(1em + 1ex);
}

button,
input {
  font-family: inherit;
  font-size: inherit;
}

kbd,
pre,
code,
.playground-write,
.playground-draw {
  font-family: var(--mono);
  font-feature-settings: normal;
  font-size: smaller;
  line-height: calc(1em + (1 / 0.8 * 1ex));
}

body {
  margin: 0;
  background-color: var(--bg);
  color: var(--fg);
}

h1,
h2,
h3,
h4,
h5,
h6,
strong,
th {
  font-weight: 700;
  letter-spacing: 0.0125em;
}

sup {
  vertical-align: top;
}

main {
  margin-block-start: calc(5.5 * (1em + 1ex));
}

dd,
.content {
  padding-inline: calc(1em + 1ex);
}

label {
  display: block;
}

h1,
h2,
h3,
h4,
h5,
h6,
label,
p,
pre,
ol,
ul,
hr,
table,
blockquote,
.block,
.frame {
  margin-block: calc(1em + 1ex);
}

summary {
  cursor: pointer;
}

.anchor {
  display: inline-block;
  width: calc(1em + 1ex);
  margin-inline-start: calc(-0.75 * (1em + 1ex));
  margin-inline-end: calc(-0.25 * (1em + 1ex));
  font-size: 1rem;
}

a[name],
h1,
h2,
h3,
h4,
h5,
h6 {
  display: block;
  scroll-margin-block-start: 6rem;
}

h1,
h2 {
  font-size: 2.5em;
  line-height: calc(1em + (1 / 2.5 * 1ex));
  margin-block: calc(1 / 2.5 * (1em + 1ex));
}

.head-article,
.foot-article,
.foot-site {
  position: relative;
}

.foot-site {
  background-color: var(--gray-0);
}

.foot-article,
.foot-site {
  margin-block-start: calc(1 * (1em + 1ex));
  border-block-start: 1px solid var(--gray-2);
}

.head-article {
  margin-block-end: calc(1 * (1em + 1ex));
}

.navigation,
.head-article {
  border-block-end: 1px solid var(--gray-2);
}

.article-row {
  display: flex;
  justify-content: space-between;
}

.article-row-start,
.article-row-end {
  font-size: smaller;
  line-height: calc(1em + (1 / 0.8 * 1ex));
  flex-basis: 0;
  flex-grow: 1;
}

.article-row-end {
  margin-inline-start: auto;
  text-align: end;
}

.foot-site {
  padding-block: 1px;
}

h3 {
  font-size: 2em;
  line-height: calc(1em + (1 / 1.5 * 1ex));
  margin-block: calc(1 / 1.5 * (1em + 1ex));
}

h4 {
  font-size: 1.25em;
  line-height: calc(1em + (1 / 1.25 * 1ex));
  margin-block: calc(1 / 1.25 * (1em + 1ex));
}

h5,
h6 {
  font-size: 1em;
  line-height: calc(1em + 1ex);
  margin-block: calc(1em + 1ex);
}

h6 {
  color: var(--gray-6);
}

img,
svg {
  max-width: 100%;
  background-color: transparent;
}

img[align='right'] {
  padding-inline-start: calc(1em + 1ex);
}

img[align='left'] {
  padding-inline-end: calc(1em + 1ex);
}

kbd {
  background-color: var(--gray-0);
  border: 1px solid var(--gray-3);
  border-radius: 3px;
  box-shadow: inset 0 -1px 0 var(--gray-4);
  color: var(--gray-9);
  padding: 0.2em 0.4em;
}

pre {
  word-wrap: normal;
  overflow: auto;
  font-size: inherit;
}

blockquote pre,
li pre {
  margin-inline: 0;
}

code {
  background-color: var(--gray-0);
}

code {
  border-radius: 3px;
  padding-block: calc(0.33 * (1 / 0.8 * 1ex));
  padding-inline: calc(0.66 * (1 / 0.8 * 1ex));
}

pre code {
  display: block;
  padding: calc(1em + 1ex) !important;
  white-space: pre;
  word-break: normal;
  overflow-x: auto;
  /* overflow: visible; */
  word-wrap: normal;

  mask-image: paint(squircle);
  --squircle-radius: 10px;
  border-radius: 10px;
}

.frame-tab-item {
  background-color: var(--gray-1);
  transition: 200ms;
  transition-property: color, background-color;
}

pre code,
.frame-body,
.frame-tab-item-selected {
  background-color: #fafafa !important; /* Color from one-light */
}

.frame-body-box {
  padding: calc(1em + 1ex);
}

.frame-tab-item-dark.frame-tab-item-selected {
  background-color: #282c34 !important;
  color: var(--white);
}

.frame-body > pre:only-child {
  margin-block: 0;
}

.frame-tab-item-inactive {
  background-color: transparent;
  color: var(--gray-6);
}

hr {
  background-color: var(--gray-1);
  border: 0;
  border-radius: 3px;
  height: calc(0.25 * (1em + 1ex));
}

table {
  border-collapse: collapse;
  border-spacing: 0;
  overflow: auto;
  width: 100%;
  font-variant-numeric: lining-nums;
}

tr {
  border-block-start: 1px solid var(--gray-3);
}

tr:nth-child(even) {
  background-color: hsl(210deg 17% 82% / 20%); /* gray-1 */
}

td,
th {
  border: 1px solid var(--gray-3);
  padding-block: calc(0.33 * (1 / 0.8 * 1ex));
  padding-inline: calc(0.66 * (1 / 0.8 * 1ex));
}

blockquote {
  color: var(--gray-6);
  margin-inline-start: 0;
  padding-inline-start: calc(1em + 1ex);
  position: relative;
}

blockquote::before {
  content: '';
  display: block;
  width: calc(0.25 * (1em + 1ex));
  height: 100%;
  background-color: var(--gray-1);
  border-radius: 3px;
  position: absolute;
  inset-inline-start: 0;
}

ol,
ul {
  padding-inline-start: 0;
}

ul {
  list-style-type: circle;
}

ol {
  list-style-type: decimal;
}

ul ul,
ol ul,
ul ol,
ol ol {
  margin-block: 0;
}

ul ul {
  list-style-type: disc;
}

ul ul ul {
  list-style-type: square;
}

ol ol {
  list-style-type: lower-roman;
}

ol ol ol {
  list-style-type: lower-alpha;
}

li {
  word-wrap: break-all;
  margin-block: calc(0.25 * (1em + 1ex));
  margin-inline-start: calc(1em + 1ex);
}

.task-list-item {
  list-style-type: none;
  margin-inline-start: 0;
}

.task-list-item input {
  margin: 0;
  margin-inline-end: calc(0.25 * (1em + 1ex));
}

dt {
  font-style: italic;
  margin-block-end: 0;
}

dt + dt {
  margin-block-start: 0;
}

dd {
  margin-block-start: 0;
}

a {
  color: var(--hl);
  transition: 200ms;
  transition-property: color;
}

a.alt {
  color: var(--purple-5);
}

.navigation a {
  display: block;
  color: inherit;
  text-decoration: none;
}

a[aria-current],
a:hover,
a:focus {
  color: inherit;
  text-decoration: none;
}

nav a[aria-current],
nav a:hover,
nav a:focus {
  color: var(--hl);
  text-decoration: underline;
}

button,
a.cta {
  outline: 0;
  padding: calc(0.25 * (1em + 1ex)) calc(0.5 * (1em + 1ex));
  border-radius: 3px;
  border: 1px solid currentColor;
  color: var(--black);
  transition: 200ms;
  transition-property: color, background-color, border-color, box-shadow;
  font-weight: 400;
  background-color: transparent;
}

a.cta:hover,
a.cta:focus,
a.cta:active,
button:hover,
button:focus,
button:active {
  color: var(--hl);
}

a.cta:active,
button:active,
a.cta.active,
button.active {
  background-color: var(--hl);
  border-color: var(--hl);
  color: var(--white);
}

a.cta:active,
a.cta.active,
a.cta:focus,
button.active,
button:active,
button:focus {
  box-shadow: 0 0 0 0.2em rgb(191 135 0 / 30%); /* --hl */
}

a.cta.success,
button.success {
  background-color: var(--green-5);
  border-color: var(--green-5);
  box-shadow: 0 0 0 0.2em rgb(26 127 55 / 30%); /* --green-5 */
  color: var(--white);
}

.content {
  width: 100%;
  max-width: calc(36 * (1em + 1ex));
  margin: calc(1 * (1em + 1ex)) auto;
}

.navigation {
  position: fixed;
  inset-inline: 0;
  inset-block-start: 0;
  display: flex;
  padding: calc(0.5 * (1em + 1ex));
  padding-top: calc(2 * (1em + 1ex));
}

.navigation::before,
.DocSearch-Container::before {
  content: '';
  inset: 0;
  position: absolute;
  z-index: 2;
  background-image: radial-gradient(
    ellipse at 50% 0%,
    hsl(39deg 97% 88% / 90%) 0%,
    hsl(39deg 97% 96% / 90%) 100%
  );
}

.DocSearch li {
  margin: 0;
}

#banner {
  padding: calc(0.25 * (1em + 1ex));
  background-color: var(--mdx-yellow);
  color: var(--white);
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  text-align: center;
  z-index: 10;
  font-weight: bolder;
  letter-spacing: 1px;
}

.full-bleed {
  width: 100vw;
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  padding-inline: calc(1em + 1ex);
}

/* Note that the `backdrop-filter` itself is applied in light mode. */
@supports (backdrop-filter: blur(1ex)) {
  .navigation::before,
  .DocSearch-Container::before {
    backdrop-filter: saturate(200%) blur(1ex);
    background-image: radial-gradient(
      ellipse at 50% 0%,
      hsl(39deg 97% 88% / 60%) 0%,
      hsl(39deg 97% 98% / 60%) 80%
    );
  }
}

.DocSearch-Modal,
.navigation-primary,
.navigation-secondary,
.navigation-search,
.navigation-tertiary {
  z-index: 3;
}

.navigation .icon {
  display: block;
  width: auto;
  height: calc(1em + 1ex);
}

.navigation-primary,
.navigation-secondary,
.navigation-tertiary,
.navigation-primary h1,
.navigation-secondary li,
.navigation-tertiary li {
  margin: 0;
}

.navigation-primary,
.navigation-secondary,
.navigation-search,
.navigation-tertiary {
  margin: 0;
  padding: calc(0.5 * (1em + 1ex));
  display: flex;
  list-style-type: none;
}

.navigation-search {
  padding: calc(0.25em + 0.25ex);
}

.DocSearch-Button {
  margin: 0 !important;
}

.navigation-primary h1,
.navigation-secondary li,
.navigation-tertiary li {
  padding: 0;
}

.navigation-primary h1 {
  font-size: 1em;
  border-bottom-width: 0;
}

.navigation-tertiary {
  justify-content: flex-end;
}

.navigation-secondary {
  z-index: 3;
  overflow-x: auto;
  overflow-y: hidden;
  flex: 1;
  flex-direction: row;
  align-items: stretch;
  flex-grow: 1;
  mask-image: linear-gradient(
    to right,
    transparent,
    black 2ex,
    black calc(100% - 2ex),
    transparent
  );
}

.navigation-secondary li {
  white-space: nowrap;
}

.navigation-secondary li + li {
  padding-inline-start: calc(0.5 * (1em + 1ex));
}

/* Some extra spacing because otherwise the blur is shown over it. */
.navigation-secondary li:last-child {
  padding-inline-end: calc(0.5 * (1em + 1ex));
}

.navigation-secondary ol,
.navigation-show-big {
  display: none;
}

.navigation-tertiary li + li {
  padding-inline-start: calc(0.5 * (1em + 1ex));
}

.skip-to-navigation {
  inset-block-start: 0;
  inset-inline-start: 0;
}

.skip-to-content,
.skip-to-navigation {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
}

.skip-to-content:focus,
.skip-to-navigation:focus {
  z-index: 4;
  width: auto;
  height: auto;
  clip: auto;
  background-color: var(--hl);
  color: var(--white);
  padding: calc(1em + 1ex);
}

.note {
  color: var(--gray-9);
  font-size: smaller;
  line-height: calc(1em + (1 / 0.8 * 1ex));
  padding-inline: calc(1 / 0.8 * (1em + 1ex));
  margin-block: calc(1 / 0.8 * (1em + 1ex));
  position: relative;
  z-index: 0;
  inset: 0;
  mask-image: paint(squircle);
  --squircle-radius: 10px;
  border-radius: 10px;
  border: 1px solid transparent;

  /* Actually the border color: */
  background-color: var(--purple-5);
}

.note::after {
  content: '';
  position: absolute;
  mask-image: paint(squircle);
  z-index: -1;
  background-color: hsl(9deg 64% 8%);
  inset: 0;
  --squircle-radius: 9px;
  border-radius: 9px;

  background-color: var(--purple-0);
}

.legacy {
  background-color: var(--gray-5);
}

.legacy::after {
  background-color: var(--gray-0);
}

.important {
  background-color: var(--red-5);
}

.important::after {
  background-color: var(--red-0);
}

.card {
  display: block;
  padding: calc(1 * (1em + 1ex));
  margin-block: calc(2 * (1em + 1ex));
  overflow: hidden;
  /* yellow */
  background-image:
    radial-gradient(
      ellipse at 0% 0%,
      rgb(252 180 45 / 5%) 20%,
      rgb(252 180 45 / 0%) 80%
    ),
    /* purple */
      radial-gradient(
        ellipse at 0% 100%,
        rgb(130 80 223 / 5%) 20%,
        rgb(130 80 223 / 0%) 80%
      );

  mask-image: paint(squircle);
  --squircle-radius: 20px;
  border-radius: 20px;
}

.emoji-list > ul {
  list-style-type: none;
}

.emoji-list > ul > li {
  margin-inline-start: 0;
}

.big {
  font-size: larger;
  line-height: calc(1em + (1 / 1.2 * 1ex));
  padding: calc(1 / 1.2 * (1em + 1ex));
  margin-block: calc(1 / 1.2 * (1em + 1ex));
}

.frame {
  /* gray-1 is used for unselected tabs, but gray-2 is really too much
   * This is a perfect mix between the two: */
  background-color: hsl(210, 20.5%, 88.8%);
  position: relative;

  mask-image: paint(squircle);
  --squircle-radius: 10px;
  border-radius: 10px;
}

.frame-resizeable {
  display: flex;
  flex-direction: column;
  overflow: auto;

  min-height: 10rem;
  height: 24rem;
  resize: vertical;
}

.frame-tab-bar {
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  margin-block-start: calc(1em + 1ex);
  list-style-type: none;
  margin: 0;
  padding: calc(0.25em + 0.25ex);
  padding-block-end: 0;
}

.frame-tab-bar-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  mask-image: linear-gradient(
    to right,
    hsl(0deg 0% 100% / 30%),
    black calc(0.5 * (1em + 1ex)),
    black calc(100% - 0.5 * (1em + 1ex)),
    hsl(0deg 0% 100% / 30%)
  );
}

.frame-body {
  border-bottom-left-radius: 3px;
  border-bottom-right-radius: 3px;
}

.frame-body > pre {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.frame-body > pre > code {
  overflow-x: auto;
  overflow-y: auto;
}

.frame-tab-bar + pre,
.frame-tab-bar + .highlight > pre {
  margin-block-start: 0;
}

.frame-tab-bar + pre code,
.frame-tab-bar + .highlight > pre code {
  --squircle-radius: 0;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.frame-tab-item {
  font-family: var(--mono);
  font-size: smaller;
  line-height: calc(1em + (1 / 0.8 * 1ex));
  padding-block: calc(1 / 0.8 * 0.25 * (1em + 1ex));
  padding-inline: calc(1 / 0.8 * 0.5 * (1em + 1ex));
  margin: calc(1 / 0.8 * 0.25 * (1em + 1ex));
  margin-block-end: 0;
  border-top-left-radius: 2px;
  border-top-right-radius: 2px;
  white-space: nowrap;
}

.frame-tab-item-language {
  margin-left: auto;
  padding-inline: 0;
}

.code-frame .copy-button {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 0;
  /* Lines it out nicely if there’s just one line of code. */
  margin: calc(0.618 * (1em + 1ex));
  backdrop-filter: saturate(200%) blur(1ex);
}

#markdown-for-thecomponent-era {
  font-weight: 600;
}

#markdown-for-thecomponent-era strong {
  color: var(--mdx-yellow);
}

.home hr {
  height: 0;
  background-color: transparent;
}

.home-preview {
  position: relative;
  border: 1px solid transparent;
  padding: calc(1em + 1ex);
  background-color: var(--gray-2);
  mask-image: paint(squircle);
  z-index: 0;
  --squircle-radius: 10px;
  border-radius: 10px;
}

.home-preview::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--bg);
  mask-image: paint(squircle);
  --squircle-radius: 9px;
  border-radius: 9px;
}

:is(.home-preview, .card, .frame-body, .nav-description, .big-columns > *)
  > :is(h1, h2, h3, h4, p, .block):first-child {
  margin-block-start: 0;
}

:is(.home-preview, .card, .frame-body, .nav-description, .big-columns > *)
  > :is(h1, h2, h3, h4, p, .block):last-child {
  margin-block-end: 0;
}

.home .anchor {
  display: none;
}

.snowfall {
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.snowfall-bar {
  flex-basis: 0;
  flex-grow: 1;
  margin: calc(0.125 * (1em + 1ex));
  background-color: var(--fg);
}

details {
  border: 1px solid var(--gray-2);
  padding: 1ex;
  border-radius: 3px;
}

details[open] {
  padding: calc(1em + 1ex);
}

.rehype-twoslash-completion-deprecated {
  opacity: 0.5;
}

.rehype-twoslash-popover-target {
  cursor: default;
}

.highlight:is(:hover, :focus-within) .rehype-twoslash-popover-target {
  background-color: var(--gray-2);
}

/* Wavy underline for errors. */
.rehype-twoslash-error-target {
  background-repeat: repeat-x;
  background-position: bottom left;
  background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 3" enable-background="new 0 0 6 3" height="3" width="6"><g fill="%23c94824"><polygon points="5.5,0 2.5,3 1.1,3 4.1,0"/><polygon points="4,0 6,2 6,0.6 5.4,0"/><polygon points="0,2 1,3 2.4,3 0,0.6"/></g></svg>');
}

/* The content that will be shown in the tooltip. */
.rehype-twoslash-popover {
  position: absolute;
  max-width: calc(45 * (1em + 1ex));
  padding: calc(0.5 * (1em + 1ex));
  margin: 0;
  background-color: var(--bg);
  border: 1px solid var(--gray-2);
  border-radius: 3px;
}

/* No padding if we have a padded code block (and perhaps more blocks) */
.rehype-twoslash-popover:has(.rehype-twoslash-popover-code) {
  padding: 0;
}

.rehype-twoslash-popover-code {
  margin: 0;
}

.rehype-twoslash-popover-code > code {
  mask-image: none;
  border-radius: 0;
}

.rehype-twoslash-popover-description {
  background-color: var(--bg);
  padding: 0 1em;
}

@media (prefers-color-scheme: dark) {
  :root {
    --white: #f0f6fc;
    --black: #010409;
    --gray-0: var(--white);
    --gray-1: #c9d1d9;
    --gray-2: #b1bac4;
    --gray-3: #8b949e;
    --gray-4: #6e7681;
    --gray-5: #484f58;
    --gray-6: #30363d;
    --gray-7: #21262d;
    --gray-8: #161b22;
    --gray-9: #0d1117;
    --hl: var(--mdx-yellow);
    --fg: var(--white);
    --bg: var(--black);

    --docsearch-key-gradient: #eaeef2 !important;
  }

  .navigation-secondary a {
    display: initial;
  }

  .note {
    color: var(--gray-0);
  }

  .note::after {
    background-color: var(--purple-9);
  }

  .legacy::after {
    background-color: var(--gray-9);
  }

  .important::after {
    background-color: var(--red-9);
  }

  .navigation::before {
    background-image: radial-gradient(
      ellipse at 50% 0%,
      hsl(39deg 97% 12% / 90%) 0%,
      hsl(39deg 97% 4% / 90%) 100%
    );
  }

  /* Note that the `backdrop-filter` itself is applied in light mode. */
  @supports (backdrop-filter: blur(1ex)) {
    .navigation::before {
      background-image: radial-gradient(
        ellipse at 50% 0%,
        hsl(39deg 97% 12% / 60%) 0%,
        hsl(39deg 97% 4% / 60%) 90%
      );
    }
  }

  .card {
    /* yellow */
    background-image:
      radial-gradient(
        ellipse at 0% 0%,
        rgb(252 180 45 / 10%) 20%,
        rgb(252 180 45 / 0%) 80%
      ),
      /* purple */
        radial-gradient(
          ellipse at 0% 100%,
          rgb(130 80 223 / 10%) 20%,
          rgb(130 80 223 / 0%) 80%
        );
  }

  .foot-article,
  .foot-site {
    border-top-color: var(--gray-6);
  }

  .navigation,
  .head-article {
    border-bottom-color: var(--gray-6);
  }

  .home-preview {
    background-color: var(--gray-6);
  }

  .foot-site {
    background-color: var(--gray-8);
  }

  .highlight:is(:hover, :focus-within) .rehype-twoslash-popover-target {
    background-color: var(--gray-5);
  }

  .rehype-twoslash-popover {
    border-color: var(--gray-6);
  }

  h6 {
    color: var(--gray-3);
  }

  kbd {
    background-color: var(--black);
    border-color: var(--gray-6);
    box-shadow: inset 0 -1px 0 var(--gray-6);
    color: var(--gray-0);
  }

  code {
    background-color: var(--gray-6);
  }

  .frame {
    background-color: var(--gray-9);
  }

  .frame-tab-item {
    background-color: var(--gray-8);
  }

  pre code,
  .frame-body,
  .frame-tab-item-selected,
  .frame-tab-item-dark.frame-tab-item-selected {
    background-color: var(--gray-7) !important;
  }

  .frame-tab-item-inactive {
    background-color: transparent;
    color: var(--gray-3);
  }

  hr {
    background-color: var(--gray-6);
  }

  tr {
    background-color: var(--gray-9);
    border-top-color: var(--gray-6);
  }

  tr:nth-child(2n) {
    background-color: var(--gray-8);
    color: var(--white);
  }

  td,
  th {
    border-color: var(--gray-4);
  }

  blockquote {
    color: var(--gray-2);
  }

  blockquote::before {
    background-color: var(--gray-4);
  }

  a.cta,
  button {
    color: var(--gray-0);
    border-color: currentColor;
    background-color: transparent;
  }

  a.cta:hover,
  a.cta:focus,
  a.cta:active,
  button:hover,
  button:focus,
  button:active {
    border-color: var(--hl);
  }

  a.cta:active,
  button:active {
    background-color: var(--hl);
    color: var(--gray-0);
  }

  a.cta.success,
  button.success {
    background-color: var(--green-5);
    border-color: var(--green-5);
    color: var(--white);
  }

  details {
    border-color: var(--gray-6);
  }
}

@media (min-width: 22em) {
  #markdown-for-thecomponent-era {
    font-size: 2rem;
    line-height: calc(1em + (1 / 2 * 1ex));
    margin-block: calc(1 / 2 * (1em + 1ex));
  }
}

@media (min-width: 40em) {
  html {
    font-size: 1.125em;
  }

  .navigation-search {
    padding: calc(0.3em + 0.3ex);
  }

  #markdown-for-thecomponent-era {
    font-size: 3rem;
    line-height: calc(1em + (1 / 3 * 1ex));
    margin-block: calc(1 / 3 * (1em + 1ex));
    padding-block: calc(1 / 3 * (1em + 1ex));
  }

  .foot-article,
  .foot-site {
    margin-block-start: calc(2 * (1em + 1ex));
  }

  .head-article {
    margin-block-end: calc(2 * (1em + 1ex));
  }

  .foot-site {
    padding-block: calc(1 * (1em + 1ex));
  }

  .big {
    padding: calc(2 * (1em + 1ex));
  }

  .big.card {
    margin-block: calc(2 * (1em + 1ex));
  }
}

@media (min-width: 56em) {
  #markdown-for-thecomponent-era {
    font-size: 5rem;
    line-height: calc(1em + (1 / 5 * 1ex));
    margin-block: calc(1 / 5 * (1em + 1ex));
    padding-block: calc(2 * 1 / 5 * (1em + 1ex));
  }

  .playground {
    display: grid;
    grid-template-columns: 49% 49%;
  }
}

@media (min-width: 64em) {
  .navigation-show-big {
    display: block;
  }

  .big {
    padding: calc(1.66 * (1em + 1ex));
  }

  .big.card {
    margin-block: calc(1.66 * (1em + 1ex));
  }

  /* Assume they don’t scroll anymore. */
  .frame-tab-bar-scroll,
  .navigation-secondary {
    mask-image: initial;
  }
}

@media (min-width: 76em) {
  #markdown-for-thecomponent-era {
    font-size: 5.9rem;
    line-height: calc(1em + (1 / 6 * 1ex));
    margin-block: calc(1 / 6 * (1em + 1ex));
  }

  .big-columns {
    display: flex;
    justify-content: space-between;
    margin: 0 calc(-1 * (1em + 1ex));
  }

  .big-columns > * {
    width: calc(15 * (1em + 1ex));
    flex: 1;
    margin: 0 calc(1em + 1ex);
  }
}

.playground {
  min-height: 40rem;
  gap: calc(1em + 1ex);
}

.playground-area,
.playground-controls,
.playground-result {
  overflow: auto;
  border-radius: 1ex;
  padding: 1em;
  margin-block: calc(1em + 1ex);
}

.playground-area {
  background-color: rgba(255, 255, 255, 0.1);
}

.playground-controls,
.playground-result {
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.playground-inner {
  position: relative;
  max-width: 100%;
  overflow: hidden;
  min-height: calc(10 * (1em + 1ex));
}

.playground-write,
.playground-draw {
  font-size: 14px;
  tab-size: 4;
  letter-spacing: normal;
  line-height: calc(1 * (1em + 1ex));
  white-space: pre-wrap;
  word-wrap: break-word;
  background: transparent;
  box-sizing: border-box;
  border: none;
  outline: none;
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  resize: none;
}

.playground-write::selection {
  color: var(--fg);
  background-color: hsl(42.22deg 74.31% 57.25% / 66%);
}

.playground-write {
  position: absolute;
  top: 0;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
  color: transparent;
  caret-color: var(--hl);
}

.playground-controls fieldset {
  border: 0;
  padding: 0;
  margin-inline: 0;
}

.playground-controls fieldset[disabled] {
  opacity: 0.6;
}

.playground-controls label {
  font-size: smaller;
  display: block;
  margin-block: calc(0.5 * (1em + 1ex));
}

.playground-controls select {
  padding: 0.5ex;
}

/* Can’t have bold things; they mess with the textarea */
.playground .pl-mh,
.playground .pl-mh .pl-en,
.playground .pl-ms {
  font-weight: normal !important;
}


================================================
FILE: docs/_asset/index.js
================================================
/* eslint-disable unicorn/prefer-query-selector */
/// <reference lib="dom" />

import docsearch_ from '@docsearch/js'
import {computePosition, shift} from '@floating-ui/dom'
import copyToClipboard from 'copy-to-clipboard'
import {ok as assert} from 'devlop'

// Squircles.
if ('paintWorklet' in CSS) {
  // @ts-expect-error: TS doesn’t understand Houdini.
  CSS.paintWorklet.addModule(
    'https://www.unpkg.com/css-houdini-squircle@0.2.1/squircle.min.js'
  )
}

// Copy buttons.
const copies = Array.from(document.querySelectorAll('button.copy-button'))
const copyTemplate = document.createElement('template')
const copiedTemplate = document.createElement('template')
copyTemplate.innerHTML = `<svg
  role="img"
  aria-label="Copy"
  class="icon icon-copy"
  viewBox="0 0 16 16"
  width=16
  height=16
>
  <title>Copy</title>
  <path
    fill="currentcolor"
    fill-rule="evenodd"
    d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"
  />
  <path
    fill="currentcolor"
    fill-rule="evenodd"
    d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"
  />
</svg>`
copiedTemplate.innerHTML = `<svg
  role="img"
  aria-label="Copied!"
  class="icon icon-copy"
  viewBox="0 0 16 16"
  width=16
  height=16
>
  <title>Copied!</title>
  <path
    fill="currentcolor"
    fill-rule="evenodd"
    d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
  />
</svg>`
const copyIcon = copyTemplate.content.querySelector('svg')
const copiedIcon = copiedTemplate.content.querySelector('svg')
assert(copyIcon)
assert(copiedIcon)

for (const copy of copies) {
  assert(copy instanceof HTMLButtonElement)
  copy.type = 'button'
  copy.replaceChildren(copyIcon.cloneNode(true))
  copy.addEventListener('click', oncopyonclick)
}

const popoverTargets = /** @type {Array<HTMLElement>} */ (
  Array.from(document.querySelectorAll('.rehype-twoslash-popover-target'))
)

for (const popoverTarget of popoverTargets) {
  /** @type {NodeJS.Timeout | number} */
  let timeout = 0

  popoverTarget.addEventListener('click', function () {
    popoverShow(popoverTarget)
  })

  popoverTarget.addEventListener('mouseenter', function () {
    clearTimeout(timeout)
    timeout = setTimeout(function () {
      popoverShow(popoverTarget)
    }, 300)
  })

  popoverTarget.addEventListener('mouseleave', function () {
    clearTimeout(timeout)
  })

  if (popoverTarget.classList.contains('rehype-twoslash-autoshow')) {
    popoverShow(popoverTarget)
  }
}

/**
 * @this {HTMLButtonElement}
 *   Button element.
 * @returns {undefined}
 *   Nothing.
 */
function oncopyonclick() {
  assert(copyIcon)
  assert(copiedIcon)
  assert(this instanceof HTMLButtonElement)

  const value = this.dataset.value
  assert(value !== undefined)

  this.classList.add('success')
  this.replaceChildren(copiedIcon.cloneNode(true))

  copyToClipboard(value)

  setTimeout(() => {
    this.classList.remove('success')
    this.replaceChildren(copyIcon.cloneNode(true))
  }, 2000)
}

/**
 * @param {HTMLElement} popoverTarget
 *   Popover target.
 * @returns {undefined}
 *   Nothing.
 */
function popoverShow(popoverTarget) {
  const id = popoverTarget.dataset.popoverTarget
  if (!id) return
  const popover = document.getElementById(id)
  if (!popover) return

  popover.showPopover()

  computePosition(popoverTarget, popover, {
    placement: 'bottom',
    middleware: [shift({padding: 5})]
  }).then(
    /**
     * @param {{x: number, y: number}} value
     */
    function (value) {
      popover.style.left = value.x + 'px'
      popover.style.top = value.y + 'px'
    }
  )
}

// Docsearch.
// Note: types are wrong.
const docsearch = /** @type {import('@docsearch/js')['default']} */ (
  /** @type {unknown} */ (docsearch_)
)

docsearch({
  appId: 'B0O9AAZ9L2',
  apiKey: '71f38eae605e3e6d500368617e32c19f',
  container: '#docsearch',
  indexName: 'mdxjs'
})


================================================
FILE: docs/_component/blog.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 * @import {Item} from './sort.js'
 */

/**
 * @typedef EntryProperties
 *   Properties for `BlogEntry`.
 * @property {Readonly<Item>} item
 *   Item.
 *
 * @typedef GroupProperties
 *   Properties for `BlogGroup`.
 * @property {string | undefined} [className]
 *   Class name.
 * @property {ReadonlyArray<Item>} items
 *   Items.
 * @property {string | undefined} [sort]
 *   Fields to sort on.
 */

import {apStyleTitleCase} from 'ap-style-title-case'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import React from 'react'
import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
import {sortItems} from './sort.js'

const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'})

/**
 * @param {Readonly<EntryProperties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function BlogEntry(properties) {
  const {item} = properties
  const {data, name} = item
  const {matter = {}, meta = {}} = data
  const title = matter.title || meta.title
  const defaultTitle = apStyleTitleCase(
    name.replace(/\/$/, '').split('/').pop()
  )
  const description = matter.description || meta.description
  const time = (
    meta.readingTime
      ? Array.isArray(meta.readingTime)
        ? meta.readingTime
        : [meta.readingTime, meta.readingTime]
      : []
  ).map(function (d) {
    return Math.ceil(d)
  })
  /** @type {string | undefined} */
  let timeLabel

  if (time.length > 1 && time[0] !== time[1]) {
    timeLabel = time[0] + '-' + time[1] + ' minutes'
  } else if (time[0]) {
    timeLabel = time[0] + ' minute' + (time[0] > 1 ? 's' : '')
  }

  return (
    <div className="card">
      <h3>
        <a href={name}>{title || defaultTitle}</a>
      </h3>
      <div>
        {meta.descriptionHast ? (
          toJsxRuntime(meta.descriptionHast, {Fragment, jsx, jsxs})
        ) : description ? (
          <p>{description}</p>
        ) : undefined}
        <span>
          <a href={name}>Continue reading »</a>
        </span>
      </div>
      <div
        style={{display: 'flex', justifyContent: 'space-between'}}
        className="block"
      >
        <div>
          {meta.author ? (
            <>
              <small>By {meta.author}</small>
              <br />
            </>
          ) : undefined}
          <small>Reading time: {timeLabel}</small>
        </div>
        {meta.published && typeof meta.published === 'object' ? (
          <div style={{marginLeft: 'auto', textAlign: 'right'}}>
            <small>
              Published on{' '}
              <time dateTime={meta.published.toISOString()}>
                {dateTimeFormat.format(meta.published)}
              </time>
            </small>
          </div>
        ) : undefined}
      </div>
    </div>
  )
}

/**
 * @param {Readonly<GroupProperties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function BlogGroup(properties) {
  const {
    className,
    items,
    sort = 'navSortSelf,meta.title',
    ...rest
  } = properties
  const sorted = sortItems(items, sort)

  return (
    <>
      {sorted.map(function (d) {
        return <BlogEntry key={d.name} {...rest} item={d} />
      })}
    </>
  )
}


================================================
FILE: docs/_component/foot-site.jsx
================================================
import React from 'react'
import {config} from '../_config.js'

export function FootSite() {
  return (
    <footer className="foot-site">
      <div className="content">
        <div
          className="block"
          style={{display: 'flex', justifyContent: 'space-between'}}
        >
          <div>
            <small>
              MDX is made with ❤️ in Amsterdam, Boise, and around the 🌏
            </small>
            <br />
            <small>This site does not track you.</small>
            <br />
            <small>MIT © 2017-{new Date().getFullYear()}</small>
          </div>
          <div style={{marginLeft: 'auto', textAlign: 'right'}}>
            <small>
              Project on <a href={config.gh.href}>GitHub</a>
            </small>
            <br />
            <small>
              Site on <a href={new URL('docs/', config.ghTree).href}>GitHub</a>
            </small>
            <br />
            <small>
              Updates as <a href="/rss.xml">RSS feed</a>
            </small>
            <br />
            <small>
              Sponsor on <a href={config.oc.href}>OpenCollective</a>
            </small>
          </div>
        </div>
      </div>
    </footer>
  )
}


================================================
FILE: docs/_component/home.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 * @import {Data} from 'vfile'
 * @import {Item} from './sort.js'
 */

/**
 * @typedef {Exclude<Data['meta'], undefined>} Meta
 *
 * @typedef Properties
 *   Properties.
 * @property {string} name
 *   Name.
 * @property {ReactNode} children
 *   Children.
 * @property {Item} navigationTree
 *   Navigation tree.
 * @property {Meta} meta
 *   Meta.
 */

import React from 'react'
import {FootSite} from './foot-site.jsx'
import {NavigationSite, NavigationSiteSkip} from './nav-site.jsx'

/**
 * @param {Readonly<Properties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function Home(properties) {
  const {children, meta, name, navigationTree} = properties

  return (
    <div className="page home">
      <NavigationSiteSkip />
      <main>
        {meta.schemaOrg ? (
          <script type="application/ld+json">
            {JSON.stringify(meta.schemaOrg)}
          </script>
        ) : undefined}
        <article>
          <div className="content body">{children}</div>
        </article>
        <FootSite />
      </main>
      <NavigationSite name={name} navigationTree={navigationTree} />
    </div>
  )
}


================================================
FILE: docs/_component/icon/github.jsx
================================================
import React from 'react'

export function GitHub() {
  return (
    <svg
      role="img"
      aria-label="GitHub"
      className="icon icon-github"
      viewBox="0 0 16 16"
      width={18}
      height={18}
    >
      <title>GitHub</title>
      <path
        fill="currentcolor"
        clipRule="evenodd"
        fillRule="evenodd"
        d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"
      />
    </svg>
  )
}


================================================
FILE: docs/_component/icon/mdx.jsx
================================================
import React from 'react'

export function Mdx() {
  return (
    <svg
      role="img"
      aria-label="MDX"
      className="icon icon-mdx"
      viewBox="0 0 138 57"
      width={69}
      height={28.5}
    >
      <title>MDX</title>
      <g>
        <rect
          width="136.5"
          height="55.5"
          x=".75"
          y=".75"
          rx="4.5"
          fill="currentColor"
        />
        <g fill="none" stroke="var(--bg)" strokeWidth="6">
          <path d="M16.5 44V19L30.25 32.75l14-14v25" />
          <path d="M70.5 40V10.75" />
          <path d="M57 27.25L70.5 40.75l13.5-13.5" />
          <path d="M122.5 41.24L93.25 12M93.5 41.25L122.75 12" />
        </g>
      </g>
    </svg>
  )
}


================================================
FILE: docs/_component/icon/open-collective.jsx
================================================
import React from 'react'

export function OpenCollective() {
  return (
    <svg
      role="img"
      aria-label="OpenCollective"
      className="icon icon-opencollective"
      viewBox="0 0 40 40"
      width={18}
      height={18}
    >
      <title>OpenCollective</title>
      <path
        fill="currentcolor"
        d="M32.779 19.921a13.09 13.09 0 01-1.989 6.938l5.13 5.151c2.512-3.364 4.082-7.569 4.082-12.089 0-4.52-1.57-8.725-4.083-12.09l-5.129 5.152c1.256 1.997 1.989 4.31 1.989 6.938z"
      />
      <path
        fill="currentcolor"
        d="M20.014 32.746c-7.014 0-12.771-5.782-12.771-12.825 0-7.043 5.757-12.825 12.77-12.825 2.618 0 4.92.736 6.91 2.102l5.129-5.15c-3.35-2.524-7.537-4.1-12.038-4.1C9.022-.053.02 8.882.02 20.025.02 31.17 9.022 40 20.014 40c4.605 0 8.793-1.577 12.142-4.1l-5.129-5.151c-1.989 1.261-4.396 1.997-7.013 1.997z"
      />
    </svg>
  )
}


================================================
FILE: docs/_component/layout.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 * @import {Data} from 'vfile'
 * @import {Item} from './sort.js'
 */

/**
 * @typedef Properties
 *   Properties.
 * @property {string} name
 *   Name.
 * @property {Readonly<URL>} ghUrl
 *   GitHub URL.
 * @property {Readonly<Data['meta']> | undefined} [meta]
 *   Meta.
 * @property {Readonly<Item>} navigationTree
 *   Navigation tree.
 * @property {ReactNode} children
 *   Children.
 */

import React from 'react'
import {FootSite} from './foot-site.jsx'
import {NavigationSite, NavigationSiteSkip} from './nav-site.jsx'
import {sortItems} from './sort.js'

const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'})

/**
 * @param {Readonly<Properties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function Layout(properties) {
  const {ghUrl, name, navigationTree} = properties
  const [self, parent] = findSelfAndParent(navigationTree) || []
  const navigationSortItems = parent
    ? parent.data.navigationSortItems
    : undefined
  const siblings = parent
    ? sortItems(
        parent.children,
        typeof navigationSortItems === 'string'
          ? navigationSortItems
          : undefined
      )
    : []
  const meta = (self ? self.data.meta : properties.meta) || {}
  const index = self ? siblings.indexOf(self) : -1
  const previous = index === -1 ? undefined : siblings[index - 1]
  const next = index === -1 ? undefined : siblings[index + 1]
  const metaAuthors = meta.authors || []
  const metaTime = (
    self
      ? accumulateReadingTime(self)
      : meta.readingTime
        ? Array.isArray(meta.readingTime)
          ? meta.readingTime
          : [meta.readingTime, meta.readingTime]
        : []
  ).map(function (d) {
    return d > 15 ? Math.round(d / 5) * 5 : Math.ceil(d)
  })
  /** @type {string | undefined} */
  let timeLabel

  if (metaTime.length > 1 && metaTime[0] !== metaTime[1]) {
    timeLabel = metaTime[0] + '-' + metaTime[1] + ' minutes'
  } else if (metaTime[0]) {
    timeLabel = metaTime[0] + ' minute' + (metaTime[0] > 1 ? 's' : '')
  }

  const up =
    parent && self && parent !== navigationTree ? (
      <div>
        <a href={parent.name}>{entryToTitle(parent)}</a>
        {' / '}
        <a href={name} aria-current="page">
          {entryToTitle(self)}
        </a>
      </div>
    ) : undefined

  const back = previous ? (
    <div>
      Previous:
      <br />
      <a rel="prev" href={previous.name}>
        {entryToTitle(previous)}
      </a>
    </div>
  ) : undefined

  const forward = next ? (
    <div>
      Next:
      <br />
      <a rel="next" href={next.name}>
        {entryToTitle(next)}
      </a>
    </div>
  ) : undefined

  const edit = (
    <div>
      Found a typo? Other suggestions?
      <br />
      <a href={ghUrl.href}>Edit this page on GitHub</a>
    </div>
  )

  const published =
    meta.published && typeof meta.published === 'object' ? (
      <>
        Published on{' '}
        <time dateTime={meta.published.toISOString()}>
          {dateTimeFormat.format(meta.published)}
        </time>
      </>
    ) : undefined

  const modified =
    meta.modified && typeof meta.modified === 'object' ? (
      <>
        Modified on{' '}
        <time dateTime={meta.modified.toISOString()}>
          {dateTimeFormat.format(meta.modified)}
        </time>
      </>
    ) : undefined

  const date =
    published || modified ? (
      <div>
        {published}
        {published && modified ? <br /> : undefined}
        {modified}
      </div>
    ) : undefined

  const readingTime = timeLabel ? <>{timeLabel} read</> : undefined

  const creditsList = metaAuthors.map(function (d, i) {
    const href = d.github
      ? 'https://github.com/' + d.github
      : d.url || undefined
    return (
      <span key={d.name}>
        {i ? ', ' : ''}
        {href ? <a href={href}>{d.name}</a> : d.name}
      </span>
    )
  })

  const credits = creditsList.length > 0 ? <>By {creditsList}</> : undefined

  const info =
    readingTime || credits ? (
      <>
        {readingTime}
        {readingTime && credits ? <br /> : undefined}
        {credits}
      </>
    ) : undefined

  const header =
    up || info ? (
      <div className="block article-row">
        {up ? <div className="article-row-start">{up}</div> : undefined}
        {info ? <div className="article-row-end">{info}</div> : undefined}
      </div>
    ) : undefined

  const tail =
    edit || date ? (
      <div className="block article-row">
        {edit ? <div className="article-row-start">{edit}</div> : undefined}
        {date ? <div className="article-row-end">{date}</div> : undefined}
      </div>
    ) : undefined

  const footer =
    back || forward ? (
      <div className="block article-row">
        {back ? <div className="article-row-start">{back}</div> : undefined}
        {forward ? <div className="article-row-end">{forward}</div> : undefined}
      </div>
    ) : undefined

  return (
    <div className="page doc">
      <NavigationSiteSkip />
      <main>
        <article>
          {header ? (
            <header className="content">
              <div className="block head-article">{header}</div>
            </header>
          ) : undefined}
          <div className="content body">{properties.children}</div>
          {footer || tail ? (
            <footer className="content">
              <div className="block foot-article">
                {footer}
                {tail}
              </div>
            </footer>
          ) : undefined}
        </article>
        <FootSite />
      </main>
      <NavigationSite name={name} navigationTree={navigationTree} />
    </div>
  )

  /**
   * @param {Item} item
   *   Item.
   * @param {Item | undefined} [parent]
   *   Parent.
   * @returns {[self: Item, parent: Item | undefined] | undefined}
   *   Self and parent.
   */
  function findSelfAndParent(item, parent) {
    if (item.name === name) return [item, parent]

    let index = -1

    while (++index < item.children.length) {
      const result = findSelfAndParent(item.children[index], item)

      if (result) return result
    }
  }
}

/**
 * @param {Item} d
 *   Item.
 * @returns {string | undefined}
 *   Title.
 */
function entryToTitle(d) {
  return d.data.matter?.title || d.data.meta?.title || undefined
}

/**
 * @param {Item} d
 *   Item.
 * @returns {[number, number] | [number] | []}
 *   Reading time.
 */
function accumulateReadingTime(d) {
  const time = (d.data.meta || {}).readingTime
  /** @type {[number, number] | [number] | []} */
  const total = time ? (Array.isArray(time) ? time : [time, time]) : []

  let index = -1
  while (++index < d.children.length) {
    const childTime = accumulateReadingTime(d.children[index])
    if (childTime[0]) total[0] = (total[0] || 0) + childTime[0]
    if (childTime[1]) total[1] = (total[1] || 0) + childTime[1]
  }

  return total
}


================================================
FILE: docs/_component/nav-site.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 * @import {Item} from './sort.js'
 */

/**
 * @typedef Properties
 *   Properties.
 * @property {string} name
 *   Name.
 * @property {Readonly<Item>} navigationTree
 *   Navigation tree.
 */

import React from 'react'
import {config} from '../_config.js'
import {GitHub} from './icon/github.jsx'
import {Mdx} from './icon/mdx.jsx'
import {OpenCollective} from './icon/open-collective.jsx'
import {NavigationGroup} from './nav.jsx'

export function NavigationSiteSkip() {
  return (
    <a
      href="#start-of-navigation"
      id="start-of-content"
      className="skip-to-navigation"
    >
      Skip to navigation
    </a>
  )
}

/**
 * @param {Readonly<Properties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function NavigationSite(properties) {
  const {name, navigationTree} = properties

  return (
    <nav className="navigation" aria-label="Site navigation">
      <div id="banner">Ceasefire now! 🕊️</div>
      <a
        href="#start-of-content"
        id="start-of-navigation"
        className="skip-to-content"
      >
        Skip to content
      </a>
      <div className="navigation-primary">
        <a href="/" aria-current={name === '/' ? 'page' : undefined}>
          <h1>
            <Mdx />
          </h1>
        </a>
      </div>
      <div className="navigation-search">
        <div id="docsearch" />
      </div>
      <NavigationGroup
        className="navigation-secondary"
        items={navigationTree.children}
        name={name}
      />
      <ol className="navigation-tertiary">
        <li>
          <a href={config.gh.href}>
            <GitHub />
          </a>
        </li>
        <li className="navigation-show-big">
          <a href={config.oc.href}>
            <OpenCollective />
          </a>
        </li>
      </ol>
    </nav>
  )
}


================================================
FILE: docs/_component/nav.jsx
================================================
// Augment vfile data:
/// <reference types="rehype-infer-description-meta" />

/**
 * @import {ElementContent} from 'hast'
 * @import {ReactNode} from 'react'
 * @import {Item} from './sort.js'
 */

/**
 * @typedef ItemProperties
 *   Properties for `NavigationItem`.
 * @property {boolean | undefined} [includeDescription=false]
 *   Whether to include the description (default: `false`).
 * @property {boolean | undefined} [includePublished=false]
 *   Whether to include the published date (default: `false`).
 * @property {Readonly<Item>} item
 *   Item.
 * @property {string | undefined} [name]
 *   Name.
 *
 * @typedef GroupOnlyProperties
 *   Properties for `NavigationGroup`;
 *   Other fields are passed to `NavigationItem`.
 * @property {string | undefined} [className]
 *   Class name.
 * @property {ReadonlyArray<Item>} items
 *   Items.
 * @property {string | undefined} [sort]
 *   Fields to sort on.
 * @property {string | undefined} [name]
 *   Name.
 *
 * @typedef {Omit<ItemProperties, 'item'> & GroupOnlyProperties} GroupProperties
 *   Properties for `NavigationGroup`.
 */

import {apStyleTitleCase} from 'ap-style-title-case'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import React from 'react'
import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
import {sortItems} from './sort.js'

const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'})

/**
 * @param {Readonly<GroupProperties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function NavigationGroup(properties) {
  const {
    className,
    items,
    sort = 'navSortSelf,meta.title',
    ...rest
  } = properties

  return (
    <ol {...{className}}>
      {sortItems(items, sort).map(function (d) {
        return <NavigationItem key={d.name} {...rest} item={d} />
      })}
    </ol>
  )
}

/**
 * @param {Readonly<ItemProperties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function NavigationItem(properties) {
  const {
    includeDescription,
    includePublished,
    item,
    name: activeName
  } = properties
  const {children, data = {}, name} = item
  const {matter = {}, meta = {}, navExcludeGroup, navigationSortItems} = data
  const title = matter.title || meta.title
  const defaultTitle = apStyleTitleCase(
    name.replace(/\/$/, '').split('/').pop()
  )
  /** @type {ReactNode} */
  let description
  /** @type {string | undefined} */
  let published

  if (includeDescription) {
    if (meta.descriptionHast) {
      // Cast because we don’t expect doctypes.
      const children = /** @type {Array<ElementContent>} */ (
        meta.descriptionHast.children
      )

      description = toJsxRuntime(
        {
          type: 'element',
          tagName: 'div',
          properties: {className: ['nav-description']},
          children
        },
        {Fragment, jsx, jsxs}
      )
    } else {
      description = matter.description || meta.description || undefined

      description &&= (
        <div className="nav-description">
          <p>{description}</p>
        </div>
      )
    }
  }

  const pub = matter.published || meta.published

  if (includePublished && pub) {
    published = dateTimeFormat.format(
      typeof pub === 'string' ? new Date(pub) : pub || undefined
    )
  }

  return (
    <li>
      {title ? (
        <a href={name} aria-current={name === activeName ? 'page' : undefined}>
          {title}
        </a>
      ) : (
        defaultTitle
      )}
      {published ? ' — ' + published : undefined}
      {description || undefined}
      {!navExcludeGroup && children.length > 0 ? (
        <NavigationGroup
          items={children}
          sort={
            typeof navigationSortItems === 'string'
              ? navigationSortItems
              : undefined
          }
          name={activeName}
        />
      ) : undefined}
    </li>
  )
}


================================================
FILE: docs/_component/note.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 */

/**
 * @typedef {'important' | 'info' | 'legacy'} NoteType
 *   Type.
 *
 * @typedef Properties
 *   Properties for `Note`.
 * @property {NoteType} type
 *   Kind.
 * @property {Readonly<ReactNode>} children
 *   Children.
 */

import React from 'react'

/** @type {Set<NoteType>} */
const known = new Set(['info', 'legacy', 'important'])

/**
 * @param {Readonly<Properties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function Note(properties) {
  const {children, type} = properties
  const className = ['note']

  if (known.has(type)) className.push(type)
  else {
    throw new Error('Unknown note type `' + type + '`')
  }

  return <div className={className.join(' ')}>{children}</div>
}


================================================
FILE: docs/_component/snowfall.jsx
================================================
/**
 * @import {ReactNode} from 'react'
 */

/**
 * @typedef Properties
 *   Properties.
 * @property {string} color
 *   Color.
 * @property {number} year
 *   Year.
 */

import React from 'react'

const data = [6, 5, 2, 4.5, 1.5, 2.5, 2, 2.5, 1.5, 2.5, 3.5, 7]

/**
 * @param {Readonly<Properties>} properties
 *   Properties.
 * @returns {ReactNode}
 *   Element.
 */
export function Chart(properties) {
  return (
    <div className="snowfall">
      {data.map(function (d) {
        return (
          <div
            key={d}
            className="snowfall-bar"
            style={{
              backgroundColor: properties.color,
              height: 'calc(' + d + ' * 0.5 * (1em + 1ex))'
            }}
          />
        )
      })}
    </div>
  )
}


================================================
FILE: docs/_component/sort.js
================================================
/**
 * @import {Data} from 'vfile'
 */

/**
 * @typedef Item
 *   Item.
 * @property {string} name
 *   Name.
 * @property {Readonly<Data>} data
 *   Data.
 * @property {Array<Item>} children
 *   Children.
 */

import dlv from 'dlv'

const collator = new Intl.Collator('en').compare

/**
 * @param {ReadonlyArray<Item>} items
 *   Items.
 * @param {string | undefined} [sortString]
 *   Fields to sort on (default: `'navSortSelf,meta.title'`).
 * @returns {ReadonlyArray<Item>}
 *   Items.
 */
export function sortItems(items, sortString = 'navSortSelf,meta.title') {
  /** @type {ReadonlyArray<[string, 'asc' | 'desc']>} */
  const fields = sortString.split(',').map(function (d) {
    const [field, order = 'asc'] = d.split(':')

    if (order !== 'asc' && order !== 'desc') {
      throw new Error('Cannot order as `' + order + '`')
    }

    return [field, order]
  })

  return [...items].sort(function (left, right) {
    let index = -1

    while (++index < fields.length) {
      const [field, order] = fields[index]
      /** @type {unknown} */
      let a = dlv(left.data, field)
      /** @type {unknown} */
      let b = dlv(right.data, field)

      // Dates.
      if (a && typeof a === 'object' && 'valueOf' in a) a = a.valueOf()
      if (b && typeof b === 'object' && 'valueOf' in b) b = b.valueOf()

      const score =
        typeof a === 'string' && typeof b === 'string'
          ? collator(a, b)
          : typeof a === 'number' && typeof b === 'number'
            ? a - b
            : (a === null || a === undefined) && (b === null || b === undefined)
              ? 0
              : a === null || a === undefined
                ? 1
                : b === null || b === undefined
                  ? -1
                  : 0

      if (score) return order === 'asc' ? score : -score
    }

    return 0
  })
}


================================================
FILE: docs/_config.js
================================================
const site = new URL('https://mdxjs.com')
const git = new URL('../', import.meta.url)
const gh = new URL('https://github.com/mdx-js/mdx/')

export const config = {
  author: 'MDX contributors',
  color: '#010409',
  gh,
  ghBlob: new URL('blob/main/', gh),
  ghTree: new URL('tree/main/', gh),
  git,
  input: new URL('docs/', git),
  oc: new URL('https://opencollective.com/unified'),
  output: new URL('public/', git),
  site,
  tags: ['mdx', 'markdown', 'jsx', 'oss', 'react'],
  title: 'MDX'
}

/** @type {Record<string, string>} */
export const redirect = {
  '/about/index.html': '/community/about/',
  '/advanced/index.html': '/guides/',
  '/advanced/api/index.html': '/packages/mdx/#api',
  '/advanced/ast/index.html': '/packages/remark-mdx/#syntax-tree',
  '/advanced/components/index.html': '/docs/using-mdx/',
  '/advanced/contributing/index.html': '/community/contribute/',
  '/advanced/custom-loader/index.html': '/guides/frontmatter/',
  '/advanced/retext-plugins/index.html': '/docs/extending-mdx/#using-plugins',
  '/advanced/plugins/index.html': '/docs/extending-mdx/',
  '/advanced/runtime/index.html': '/packages/mdx/#evaluatefile-options',
  '/advanced/specification/index.html': '/packages/remark-mdx/#syntax-tree',
  '/advanced/sync-api/index.html': '/packages/mdx/#api',
  '/advanced/transform-content/index.html': '/packages/remark-mdx/',
  '/advanced/typescript/index.html': '/docs/getting-started/#types',
  '/advanced/writing-a-plugin/index.html': '/guides/frontmatter/',
  '/contributing/index.html': '/community/contribute/',
  '/editor-plugins/index.html': '/docs/getting-started/#editor',
  '/editors/index.html': '/docs/getting-started/#editor',
  '/getting-started/create-react-app/index.html': '/docs/getting-started/#vite',
  '/getting-started/gatsby/index.html': '/docs/getting-started/#gatsby',
  '/getting-started/next/index.html': '/docs/getting-started/#nextjs',
  '/getting-started/parcel/index.html': '/docs/getting-started/#parcel',
  '/getting-started/react-static/index.html': '/docs/getting-started/#vite',
  '/getting-started/table-of-components/index.html': '/table-of-components/',
  '/getting-started/typescript/index.html': '/docs/getting-started/#types',
  '/getting-started/webpack/index.html': '/docs/getting-started/#webpack',
  '/getting-started/index.html': '/docs/getting-started/',
  '/guides/custom-loader/index.html': '/guides/frontmatter/',
  '/guides/live-code/index.html':
    '/guides/syntax-highlighting/#syntax-highlighting-with-the-meta-field',
  '/guides/markdown-in-components/index.html': '/docs/what-is-mdx/',
  '/guides/math-blocks/index.html': '/guides/math/',
  '/guides/mdx-embed/index.html': '/guides/embed/#embeds-at-run-time',
  '/guides/table-of-contents/index.html': '/docs/extending-mdx/',
  '/guides/terminal/index.html': '/docs/getting-started/#ink',
  '/guides/vue/index.html': '/docs/getting-started/#vue',
  '/guides/wrapper-customization/index.html': '/docs/using-mdx/#layout',
  '/guides/writing-a-plugin/index.html':
    '/docs/extending-mdx/#creating-plugins',
  '/mdx/index.html': '/docs/what-is-mdx/',
  '/plugins/index.html': '/docs/extending-mdx/#using-plugins',
  '/projects/index.html': '/community/projects/',
  '/support/index.html': '/community/support/',
  '/syntax/index.html': '/docs/getting-started/#syntax',
  '/vue/index.html': '/docs/getting-started/#vue'
}


================================================
FILE: docs/blog/conf.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'johno', name: 'John Otander'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2020-07-31')
}

<Note type="legacy">
  **Note**: This is an old blog post.
  The below is kept as is for historical purposes.
</Note>

# MDXConf

MDXConf is a free and online conference for the MDX community.
Whether you’re just learning about MDX or an expert, there’ll be something for
you! {/* more */}

August 24th, 2020 at 8am PDT/3pm UST <br /> Online • Free

## Watch

The conference is now over, but you can still watch the recordings!

[Watch the talks →](https://egghead.io/playlists/mdx-conf-3fc2)

## About

Join us for the first MDX conference!
We’ll stream it directly to you, for free.

MDX has grown rapidly since the [first commit][] two and a half years ago.
We’d like to celebrate our accomplishments so far, and talk about what lies
ahead.
We’ve got lots of plans.

Learn how MDX increases developer productivity, improves educational
content authoring, and even peek behind the curtains to see how MDX works.

## Speakers

### Chris Biscardi

![](https://github.com/ChristopherBiscardi.png?size=200)]

Keynote: The past, present, and future of MDX

### Monica Powell

![](https://github.com/M0nica.png?size=200)

Migrating to MDX

### Laurie Barth

![](https://github.com/laurieontech.png?size=200)

MDX v2 syntax

### Cole Bemis

![](https://github.com/colebemis.png?size=200)

Demystifying MDX

### Prince Wilson

![](https://github.com/maxcell.png?size=200)

Personal site playgrounds

### Kathleen McMahon

![](https://github.com/resource11.png?size=200)

Digital gardening with MDX magic

### Rodrigo Pombo

![](https://github.com/pomber.png?size=200)

The X in MDX

### Jonathan Bakebwa

![](https://github.com/codebender828.png?size=200)

MDX and Vue/Nuxt

## Sign up

<Note type="legacy">
  **Note**: Sign up is closed.
</Note>

## FAQ

### What if I can’t make it on August 24th?

We’ll miss you, but you won’t miss out!
All talks will be recorded and released the day of the conference.
You can catch up with the talks, or rewatch them, whenever convenient.

### Will the talks be transcribed?

Yes.

### Is there a code of conduct?

Absolutely.
We’re dedicated to providing a harassment-free experience for everyone.
We will not tolerate harassment of participants in any form.
We’ve adopted the [Party Corgi Network’s Code of Conduct][coc].
We will have moderators to ensure that the code of conduct is followed.

### Do you have a different question?

Reach out to us.

[coc]: https://github.com/partycorgi/partycorgi/blob/corgi/CODE_OF_CONDUCT.md

[first commit]: https://github.com/mdx-js/mdx/commit/dee47dc20b08d534132e3b966cdccf3b88c7bca5


================================================
FILE: docs/blog/custom-pragma.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'christopherbiscardi', name: 'Chris Biscardi'}
  ],
  modified: new Date('2021-11-01'),
  published: new Date('2019-03-11')
}

<Note type="legacy">
  **Note**: This is an old blog post.
  The steps described in it are no longer performed by MDX.
  It now uses an JavaScript AST first rather than generating a string of JSX.
  It is also no longer required for extra glue code, that combines MDX with a
  specific framework, to be used on the client.
  See [§ How MDX works](/docs/using-mdx/#how-mdx-works)
  and [¶ Architecture](/packages/mdx/#architecture) for more info.
  The below is kept as is for historical purposes.
</Note>

# Custom pragma

`MDXTag`, for those that aren’t aware, is a critical piece in the way
MDX replaces HTML primitives like `<pre>` and `<h1>` with custom React
Components.
[I’ve previously
written](https://www.christopherbiscardi.com/post/codeblocks-mdx-and-mdx-utils)
about the way `MDXTag` works when trying to replace the `<pre>` tag
with a custom code component.
[mdx-utils](https://github.com/ChristopherBiscardi/gatsby-mdx/blob/00769a1b72455f40843cd2f09ee34fd63b009fb2/packages/mdx-utils/index.js)
contains the methodology for pulling the props around appropriately
through the `MDXTag` elements that are inbetween `pre` and `code`.

{/* more */}

```tsx
exports.preToCodeBlock = preProps => {
  if (
    // children is MDXTag
    preProps.children &&
    // MDXTag props
    preProps.children.props &&
    // if MDXTag is going to render a <code>
    preProps.children.props.name === 'code'
  ) {
    // we have a <pre><code> situation
    const {
      children: codeString,
      props: {className, ...props}
    } = preProps.children.props

    return {
      codeString: codeString.trim(),
      language: className && className.split('-')[1],
      ...props
    }
  }
  return undefined
}
```

So `MDXTag` is a real Component in the middle of all of the other MDX
rendered elements.
All of the code is included here for reference.

```tsx
import React, {Component} from 'react'

import {withMDXComponents} from './mdx-provider'

const defaults = {
  inlineCode: 'code',
  wrapper: 'div'
}

class MDXTag extends Component {
  render() {
    const {
      name,
      parentName,
      props: childProps = {},
      children,
      components = {},
      Layout,
      layoutProps
    } = this.props

    const Component =
      components[`${parentName}.${name}`] ||
      components[name] ||
      defaults[name] ||
      name

    if (Layout) {
      return (
        <Layout components={components} {...layoutProps}>
          <Component {...childProps}>{children}</Component>
        </Layout>
      )
    }

    return <Component {...childProps}>{children}</Component>
  }
}

export default withMDXComponents(MDXTag)
```

`MDXTag` is used in the hast to estree conversion,
which is the final step in the MDX AST pipeline.
Every renderable element is wrapped in an `MDXTag`, and `MDXTag` handles
rendering the element later.

```tsx
return `<MDXTag name="${node.tagName}" components={components}${
  parentNode.tagName ? ` parentName="${parentNode.tagName}"` : ''
}${props ? ` props={${props}}` : ''}>${children}</MDXTag>`
```

## A concrete example

The following MDX

```mdx
# a title

    and such

testing
```

turns into the following React code

```tsx
export default ({components, ...props}) => (
  <MDXTag name="wrapper" components={components}>
    <MDXTag name="h1" components={components}>{`a title`}</MDXTag>{' '}
    <MDXTag name="pre" components={components}>
      <MDXTag
        name="code"
        components={components}
        parentName="pre"
        props={{metaString: null}}
      >{`and such `}</MDXTag>
    </MDXTag>{' '}
    <MDXTag name="p" components={components}>{`testing`}</MDXTag>
  </MDXTag>
)
```

resulting in the following HTML

```html
<div>
  <h1>a title</h1>
  <pre>
    <code>and such</code>
  </pre>
  <p>testing</p>
</div>
```

## createElement

With the new approach, the above MDX transforms into this new React code

```tsx
const layoutProps = {}
export default function MDXContent({components, ...props}) {
  return (
    <MDXLayout
      {...layoutProps}
      {...props}
      components={components}
      mdxType="MDXLayout"
    >
      <h1>{`a title`}</h1>
      <pre>
        <code parentName="pre" {...{}}>{`and such
`}</code>
      </pre>
      <p>{`testing`}</p>
    </MDXLayout>
  )
}

MDXContent.isMDXComponent = true
```

Notice how now the React elements are plainly readable without
wrapping `MDXTag`.

Now that we’ve cleaned up the intermediary representation, we need to
make sure that we have the same functionality as the old `MDXTag`.
This is done through a custom `createElement` implementation.
Typically when using React, we use `React.createElement` to render the elements
on screen.
This is even true if you’re using JSX because JSX tags such as `<div>` compile
to `createElement` calls.
So this time instead of using `React.createElement` we’ll be using our own.

Reproduced here is our `createElement` function and the logic for how
we decide whether or not MDX should take over the rendering of the
`createElement` call.

```tsx
export default function (type, props) {
  const args = arguments
  const mdxType = props && props.mdxType

  if (typeof type === 'string' || mdxType) {
    const argsLength = args.length

    const createElementArgArray = new Array(argsLength)
    createElementArgArray[0] = MDXCreateElement

    const newProps = {}
    for (let key in props) {
      if (hasOwnProperty.call(props, key)) {
        newProps[key] = props[key]
      }
    }
    newProps.originalType = type
    newProps[TYPE_PROP_NAME] = typeof type === 'string' ? type : mdxType

    createElementArgArray[1] = newProps

    for (let i = 2; i < argsLength; i++) {
      createElementArgArray[i] = args[i]
    }

    return React.createElement.apply(null, createElementArgArray)
  }

  return React.createElement.apply(null, args)
}
```

## Vue

One really cool application of the new output format using a custom
`createElement` is that we can now write versions of it for Vue and other
frameworks.
Since the pragma insertion is the responsibility of the webpack (or other
bundlers) loader, swapping the pragma can be an option in mdx-loader as long as
we have a Vue `createElement` to point to.


================================================
FILE: docs/blog/index.mdx
================================================
{
  /**
   * @import {Item} from '../_component/sort.js'
   */

  /**
   * @typedef Props
   * @property {Item} navigationTree
   */
}

import assert from 'node:assert/strict'
import {BlogGroup} from '../_component/blog.jsx'

export const info = {
  author: [{name: 'MDX Contributors'}],
  modified: new Date('2024-07-04'),
  published: new Date('2021-11-01')
}
export const navExcludeGroup = true
export const navigationSortItems = 'navSortSelf,meta.published:desc'
export const navSortSelf = 7

# Blog

The latest news about MDX.

{
  (function () {
    const navigationTree = props.navigationTree
    const category = navigationTree.children.find(function (item) {
      return item.name === '/blog/'
    })
    assert(category)

    return (
      <nav>
        <BlogGroup items={category.children} sort={navigationSortItems} />
      </nav>
    )
  })()
}


================================================
FILE: docs/blog/shortcodes.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'johno', name: 'John Otander'}
  ],
  modified: new Date('2021-11-01'),
  published: new Date('2019-05-14')
}

<Note type="legacy">
  **Note**: This is an old blog post.
  The features described in it are currently documented at
  [§ MDX provider](/docs/using-mdx/#mdx-provider).
  The below is kept as is for historical purposes.
</Note>

# Shortcodes

An exciting new feature in MDX v1 is global shortcodes.
This allows you to expose components to all of your documents in your app or
website.
This is a useful feature for common components like YouTube embeds, Twitter
cards, or anything else frequently used in your documents.

{/* more */}

If you have an application wrapper for your MDX documents
you can add in components with the `MDXProvider`:

```tsx path="src/App.js"
import React from 'react'
import {MDXProvider} from '@mdx-js/react'
import {TomatoBox, Twitter, YouTube} from './ui'

const shortcodes = {TomatoBox, Twitter, YouTube}

export default ({children}) => (
  <MDXProvider components={shortcodes}>{children}</MDXProvider>
)
```

Then, any MDX document that’s wrapped in `App` has access to `YouTube`,
`Twitter`, and `TomatoBox`.
Shortcodes are nothing more than components, so you can reference them anywhere
in an MDX document with JSX.

```mdx path="example.mdx"
# Hello world!

Here’s a YouTube shortcode:

<YouTube tweetId="1234" />

Here’s a YouTube shortcode wrapped in TomatoBox:

<TomatoBox>
  <YouTube videoId="1234" />
</TomatoBox>
```

That’s it.
🎉 🚀

Huge thanks to [Chris Biscardi](https://christopherbiscardi.com)
for building out most of this functionality.


================================================
FILE: docs/blog/v1.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'johno', name: 'John Otander'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2019-04-11')
}

<Note type="legacy">
  **Note**: This is an old blog post.
  [ZEIT is now Vercel](https://rauchg.com/2020/vercel).
  An “`@mdx` pragma” is no longer needed.
  The below is kept as is for historical purposes.
</Note>

# MDX goes stable

It’s been a year and a half since the first MDX commit and a year since MDX was
first announced at ZEIT Day.
MDX is a radical paradigm shift in how to write immersive content using
components.
It’s an open, [authorable format](https://johno.com/authorable-format) that
makes it *fun* to write again.

{/* more */}

Since announcing MDX we’ve been working on numerous bug fixes, new features,
better parsing, and integration tests.
Now, we think it’s ready.
**We’re happy to finally release v1!**

## 🎉 What’s new?

Here’s a rough breakdown on what we’ve been working on:

### Parsing

MDX document parsing is significantly improved.
We won’t get into the nitty gritty here, but we’ve seen how MDX is used in
real-world projects, integrated the edge cases we came across into our test
suite, and now handle JSX, imports, and exports much more intuitively.
Please open an issue if you find a case we haven’t covered!😸

### remark-mdx

`remark-mdx` is the syntactic extension for MDX in remark.
It provides the parsing functionality for MDX as a
*[remark](https://github.com/remarkjs/remark) plugin*.
That sounds a bit meta.
What it means is that before we had the syntax parsing bits *in* the library
(unusable from the outside), and now it’s externalized (usable from the
outside).
This is useful if you want to inspect or transform MDX documents.
For example, it allows tools like prettier to use the exact same parser used by
MDX core.
Or you could use `remark-mdx` in combination with
[remark-lint](https://github.com/remarkjs/remark-lint) to check your MDX.

### Custom pragma

With v1 we’ve moved away from using `MDXTag` and are using a custom pragma which
wraps `React.createElement`.
We decided to update this approach so the JSX output is more legible,
lighterweight, and more customizable.
**This means MDX can be used with any React, Vue, Preact, or any other library
with JSX support**.

Special thanks to [@christopherbiscardi][christopherbiscardi]
for implementing this feature.

[Read the blog post](/blog/custom-pragma/)

### 📚 Documentation

**Good libraries need great docs**, so we’ve been working on adding content and
improving the overall documentation website experience.

* Search (thanks Algolia)
* [Guides](/guides/)
* [Automatic deployment via ZEIT][zeit]
* [Custom Gatsby theme][gatsbyjs]
* Reorganization of docs for intuitiveness
* Full page rewrites to improve clarity

Special thanks to [@jxnblk](https://github.com/jxnblks) and
[@wooorm][wooorm] for their help improving the docs and
updating the build tooling.

## Breaking changes

In order to make some improvements we were forced to introduce a few breaking
changes.
**These were the result of real-world production testing and feedback**.
The community has evolved and we’ve come up with newer, better ideas over the
last year.
We have made sure the impact is small and have written a full migration guide.

* 🚨`@mdx-js/tag` is replaced by `@mdx-js/react` and an `@mdx` pragma
  — [migration guide](/migrating/v1#pragma)
* MDXProvider now merges component contexts when nested
  — [migration guide](/migrating/v1#mdxprovider)
* React support now requires `>= 16.8` in `@mdx-js/react`
  — [migration guide](/migrating/v1#react)

[Read the full v1 migration guide](/migrating/v1)

### Deprecations

We only needed to introduce one deprecation.
The `mdPlugins` and `hastPlugins` options have been renamed `remarkPlugins` and
`rehypePlugins` respectively.
For the time being we will issue a warning when the old options are used.
In v2, the old options will be removed.

## 📈 Growth

A major release is always a good time to take a step back and reflect on what’s
been happening in terms of growth and the greater community.
The ecosystem surrounding MDX has already grown larger than we ever dreamed.
We’ve also seen projects/products/application we never even imagined.

### Numbers

* **Downloads**: 125,000/week, 2.4M total
* **Stars**: 6,200
* **Contributors**: 50
* **Pull requests**: 281
* **Commits**: 670

The contributor growth is one of the most important aspects here as we have
numerous community members that are familiar with MDX internals.
This allows us to continually improve the project and spread the workload
against an ever growing team of contributors.

[See the contributor graph](https://github.com/mdx-js/mdx/graphs/contributors?from=2017-12-17\&to=2019-04-11\&type=c)

### Ecosystem

* [Prettier](https://prettier.io)
* [Docz](https://docz.site)
* [MDX Deck](https://github.com/jxnblk/mdx-deck)
* [Next.js](https://nextjs.org)
* [Gatsby][gatsbyjs]
* [AST Explorer](https://astexplorer.net)
* [Vue support (alpha)](/docs/getting-started/#vue)
* [Demoboard](https://frontarm.com/demoboard/)
* [Editors](/docs/getting-started/#editor)

## 🛣 Roadmap

With v1 released we have a roadmap in place that we’ll continue working towards
over the next 6 months or so in addition to bug fixes and parsing issues we
might encounter.

* MDXs: [#454](https://github.com/mdx-js/mdx/issues/454)
* Interleaving: [#195](https://github.com/mdx-js/mdx/issues/195)
* Global shortcodes: [#508](https://github.com/mdx-js/mdx/pull/508)
* Stable Vue support: [#238](https://github.com/mdx-js/mdx/issues/238)
* Blocks: MDX WYSIWYG: [blocks/blocks][blocks]
* MDX playground inspired by AST Explorer: [#220](https://github.com/mdx-js/mdx/issues/220)
* New splash page: [#444](https://github.com/mdx-js/mdx/issues/444)
* Showcase page: [#414](https://github.com/mdx-js/mdx/issues/414)

### Vue support

Supporting Vue is an important goal for MDX and is one of the primary reasons
we’ve rearchitected MDX to use custom pragma.
We’re delighted that **we now have an alpha version for Vue working**.
We’d love it if anyone from the Vue community wants to give it a try and provide
feedback.

[See the Vue example](https://github.com/mdx-js/mdx/tree/36cb41b/examples/vue)

### Blocks project

One of the key missing aspects of authoring MDX documents is the editing
experience.
Currently, there isn’t an approachable way to write MDX unless you enjoy working
in a text editor and writing raw Markdown/code.
We’d like to solve that and have begun work on an MDX “blocks editor” that’s a
**content-focused WYSIWYG**.
Not to mention, we’ll be doing all that we can to make sure the editor is as
accessible as it can be from the beginning.

When we have a beta ready we will be open sourcing it and announcing, so stay
tuned.

[Check out the Blocks project][blocks]

## unified collective

MDX is part of the unified collective, which is an open source ecosystem for
dealing with many sources of content.
unified projects are used all over the web, and it would never be possible
without financial support from our fine sponsors.

* [ZEIT][] 🥇
* [Gatsby][gatsbyjs] 🥇
* [Holloway](https://www.holloway.com) 🥉
* [Backers](https://opencollective.com/unified#budget) 🏆
* [You?](https://opencollective.com/unified)👤

## 🙏 Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
[@wooorm][wooorm],
[@silvenon](https://github.com/silvenon),
[@timneutkens](https://github.com/timneutkens),
[@ChristopherBiscardi][christopherbiscardi],
[@jxnblk](https://github.com/jxnblk),
[@alexandernanberg](https://github.com/alexandernanberg),
[@jescalan](https://github.com/jescalan),
[@Jarred-Sumner](https://github.com/Jarred-Sumner),
[@leimonio](https://github.com/leimonio),
[@ticky](https://github.com/ticky),
[@jamesknelson](https://github.com/jamesknelson),
[@pshrmn](https://github.com/pshrmn),
[@rauchg](https://github.com/rauchg),
[@joelhooks](https://github.com/joelhooks),
[@jlengstorf](https://github.com/jlengstorf),
[@johnlindquist](https://github.com/johnlindquist),
[@kyleamathews](https://github.com/kyleamathews),
[@kentcdodds](https://github.com/kentcdodds),
[@wesbos](https://github.com/wesbos),
[@rosew](https://github.com/rosew),
[@pedronauck](https://github.com/pedronauck),
[@tayiorbeii](https://github.com/tayiorbeii),
[@nickbender](https://github.com/nickbender),
[@ntaylor89](https://github.com/ntaylor89),
[@mxstbr](https://github.com/mxstbr),
[@manovotny](https://github.com/manovotny),
[@xyc](https://github.com/xyc),
[@filoxo](https://github.com/filoxo),
[@millette](https://github.com/millette),
[@hugmanrique](https://github.com/hugmanrique),
[@johnsherrard](https://github.com/johnsherrard),
[@sw-yx](https://github.com/sw-yx),
and anyone we may have forgotten.

[blocks]: https://github.com/blocks/blocks

[christopherbiscardi]: https://github.com/christopherbiscardi

[gatsbyjs]: https://gatsbyjs.org

[wooorm]: https://github.com/wooorm

[zeit]: https://zeit.co


================================================
FILE: docs/blog/v2.mdx
================================================
import {Note} from '../_component/note.jsx'
export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2022-02-01')
}

<Note type="legacy">
  **Note**: This is an old blog post.
  The below is kept as is for historical purposes.
</Note>

<Note type="info">
  **Note**: Info on how to migrate is available in our
  [Version 2 migration guide][migrating].
</Note>

# MDX 2

Version 2 of MDX was released after years of hard work, and has many
improvements.
Here are the highlights:

{/* more */}

<div className="emoji-list">
  * 📝 **Improved syntax** makes it easier to use markdown in JSX
  * 🧑‍💻 **JavaScript expressions** turn `{2 * Math.PI}` into {2 * Math.PI}
  * 🔌 New **esbuild**, **Rollup**, and **Node.js** integrations
  * ⚛️ **Any JSX runtime**: React, Preact, Vue, Emotion, you name it, they’re
    all supported
  * 🌳 **Improved AST** exposes more info in greater detail
  * 🏃‍♀️ Compiles at least **25% faster**
  * 🚴 Generated code runs twice as fast (**100% faster**)
  * 🚄 Bundle size of `@mdx-js/mdx` is more than three times as small
    (**250% smaller**)
  * 🧵 …and much, so much more
</div>

It’s been 4 years since this project was announced.
2½ since we released our stable version 1.
**We’re proud to finally release v2!**
Let’s dive in!

## Contents

* [Improvements to the MDX format](#improvements-to-the-mdx-format)
* [Rollup, esbuild, and other integrations](#rollup-esbuild-and-other-integrations)
* [Architectural improvements](#architectural-improvements)
* [TypeScript](#typescript)
* [Docs & site](#docs--site)
* [Breaking changes](#breaking-changes)
* [Thanks](#thanks)

## Improvements to the MDX format

We’ve spent a lot of time thinking and trying out different ways to improve the
format.
Originally, the format was very close to how markdown, and HTML in markdown,
works.
We found that the old behavior often yielded unexpected results.
In version 2, we shift the format a little bit closer to how JS(X) works.

Take for example this MDX file:

```mdx chrome=no
<div>*hi*?</div>

<div>
  # hi?
</div>

<main>
  <div>

    # hi?

  </div>
</main>
```

<div className="big-columns">
  <div>
    In version 1, that was equivalent to the following JSX:

    ```tsx chrome=no
    <>
      <div>*hi*?</div>
      <div>
        # hi?
      </div>
      <main>
        <div>
          <pre><code># hi?</code></pre>
        </div>
      </main>
    </>
    ```
  </div>

  <div>
    In version 2, it’s equivalent to the following JSX:

    ```tsx chrome=no
    <>
      <div><em>hi</em>?</div>
      <div>
        <h1>hi?</h1>
      </div>
      <main>
        <div>
          <h1>hi?</h1>
        </div>
      </main>
    </>
    ```
  </div>
</div>

We believe it’s more intuitive that markdown “inlines” such as emphasis can form
between tags on the same line (first `<div>`), “blocks” such as headings can
form if they’re on their own line (second `<div>`), and indentation is allowed
rather than forming code (third `<div>`).

We also added support for JavaScript expressions, take for example:

<div className="big-columns">
  <div>
    ```mdx path="expressions.mdx"
    export const authors = [
      {name: 'Jane', email: 'hi@jane.com'},
      {name: 'John', github: '@johno'}
    ]
    export const published = new Date('2022-02-01')

    Written by: {new Intl.ListFormat('en').format(authors.map(d => d.name))}.

    Published on: {new Intl.DateTimeFormat('en', {dateStyle: 'long'}).format(published)}.
    ```
  </div>

  <div>
    ```tsx path="equivalent.jsx"
    <>
      <p>Written by: Jane and John.</p>
      <p>Published on: February 1, 2022.</p>
    </>
    ```
  </div>
</div>

As the format moves a little further from markdown towards JSX, we’ve added
support for loading “normal” markdown without our syntax extensions.
If you’re using our bundler integration `@mdx-js/loader` (or `@mdx-js/rollup`,
`@mdx-js/esbuild`, or `@mdx-js/node-loader`, see next section), then that’ll
just work: import `readme.mdx` and it’s seen as the MDX format, import
`readme.md` and it’s seen as markdown, based on their extensions.

The MDX format is described in [§ What is MDX?][what]

## Rollup, esbuild, and other integrations

When we started out, Babel, webpack, and React were ubiquitous in the JavaScript
ecosystem and we built MDX on them.
For version 2, we worked hard to make them optional.
They’re no longer required and MDX can more easily be used with other tools.

On the bundler side, we’ve added new integrations: `@mdx-js/esbuild` for
esbuild (an extremely fast bundler) and `@mdx-js/rollup` for Rollup (a bundler
that’s also used in Vite and WMR).
You can even import MDX files directly in Node.js with our new
`@mdx-js/node-loader`.

On the runtime side, we can now compile JSX away to normal JavaScript and
no longer need framework-specific code to glue them together with MDX.
Now any JSX runtime, whether [classic or automatic][jsx-runtime], is supported.
This means MDX can be used with React, Preact, Vue, Emotion, Theme UI, Ink, you
name it, plus anything that’s yet to be invented!

See [§ Getting started][getting-started] for a quick start but also in-depth
info on how to integrate MDX with many different tools.

## Architectural improvements

To make the syntax of the MDX format better and to allow new integrations and
arbitrary JSX runtimes, we’ve rewritten almost everything.
Part of that effort was [micromark][], which is another story, but it means
we’re fully CommonMark (and optionally GFM) compliant, while also understanding
more about MDX files.

Now we can throw an early error when there’s a typo and point to exactly where
it happened, instead of a later bundler like webpack complaining about an error
in an intermediate, unrecognizable, and broken string of JavaScript.
It also means that we have a new AST which describes the MDX syntax in more
detail — we even expose the embedded JavaScript.
This detailed AST allows plugins to enhance MDX in powerful new ways.
It also helped solve edge cases where MDX would previously crash.
And it let us drop Babel.

This new architecture results in **25% faster** compilation, generated code
that runs twice as fast (**100% faster**), and that the bundle size of
`@mdx-js/mdx` is more than three times as small (**250% smaller**).

See [¶ Architecture in `@mdx-js/mdx`][architecture] for more on how our compiler
works.
See [§ Extending MDX][extending] for several plugins that use the new tree to
enhance MDX, how to use them and other plugins, and how to create plugins.

## TypeScript

All [`@mdx-js/*` packages][packages] are now fully typed with [TypeScript][]
through JSDoc comments.
That means our APIs are exposed as TypeScript types but also that our projects
are type safe internally.

We’ve published [`@types/mdx`][types-mdx], a types-only package that can be used
with any (community) integration.
You can use it, if you’re importing MDX files, to type those imported
components.

See [¶ TypeScript in § Getting started][ts] for more on how to use configure
TypeScript.

## Docs & site

MDX is used and liked a lot.
Before version 1 we had amassed a total of **2.5m downloads**.
Now we hit that number every week.
Our core compiler `@mdx-js/mdx` is used in **61k projects**.
Our GitHub repo has **11.6k stars**.

Many people help, often with docs.
85 contributors committed to our repo since version 1.
We’re grateful for these contributions and all those individual insights,
but over the years it did result in some inconsistencies and duplicated content.

For version 2, we rewrote our docs from beginning to end to tell a consistent
story for new users, folks that do complex AST and compiler stuff, and
anyone in between.

We also made a new website.
It’s built on MDX of course, [unified][] itself, and [React Server Components
(RSC)][rsc].
While we dogfood the former two as they’re projects we maintain, and the
latter is extremely experimental, we think compiling things ahead of time and
betting on hybrid models, compared to completely server-side sites or completely
client-side apps, is the smart choice for us and the web’s future.

Our new site is heavily optimized and fast, gorgeous (subjective but hey), has
rich metadata, and scores very well in performance and accessibility review
tools such as Lighthouse and axe.

See [§ Contribute][contribute] for more on how to help.

## Breaking changes

When you’re ready to migrate, please see the
[Version 2 migration guide][migrating].

## Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
John Otander ([**@johno**](https://github.com/johno)),
Christian Murphy ([**@ChristianMurphy**](https://github.com/ChristianMurphy)),
JounQin ([**@JounQin**](https://github.com/JounQin)),
Jack Bates ([**@jablko**](https://github.com/jablko)),
Sam Chen ([**@chenxsan**](https://github.com/chenxsan)),
Sam Robbins ([**@samrobbins85**](https://github.com/samrobbins85)),
Remco Haszing ([**@remcohaszing**](https://github.com/remcohaszing)),
LB ([**@laurieontech**](https://github.com/laurieontech)),
Gabriel Kirkley ([**@gdgkirkley**](https://github.com/gdgkirkley)>),
Hung-I Wang ([**@Gowee**](https://github.com/Gowee)),
Ilham Wahabi ([**@iwgx**](https://github.com/iwgx)),
Kaito Sugimoto ([**@HelloRusk**](https://github.com/HelloRusk)),
Karl Horky ([**@karlhorky**](https://github.com/karlhorky)),
Katie Hughes ([**@glitteringkatie**](https://github.com/glitteringkatie)),
Lachlan Campbell ([**@lachlanjc**](https://github.com/lachlanjc)),
Marcy Sutton ([**@marcysutton**](https://github.com/marcysutton)),
Marius Gundersen ([**@mariusGundersen**](https://github.com/mariusGundersen)),
Marius-Remus Mate,
Mark Skelton ([**@mskelton**](https://github.com/mskelton)),
Martin V ([**@ndresx**](https://github.com/ndresx)),
Matija Marohnić ([**@silvenon**](https://github.com/silvenon)),
Michael Oliver ([**@michaeloliverx**](https://github.com/michaeloliverx)),
Michaël De Boey ([**@MichaelDeBoey**](https://github.com/MichaelDeBoey)),
Muescha ([**@muescha**](https://github.com/muescha)),
Norviah ([**@Norviah**](https://github.com/Norviah)),
Paul Scanlon ([**@PaulieScanlon**](https://github.com/PaulieScanlon)),
Peter Mouland ([**@peter-mouland**](https://github.com/peter-mouland)),
Prince Wilson ([**@maxcell**](https://github.com/maxcell)),
Rafael Almeida ([**@rafaelalmeidatk**](https://github.com/rafaelalmeidatk)),
Rodrez ([**@rodrez**](https://github.com/rodrez)),
Rongjian Zhang ([**@pd4d10**](https://github.com/pd4d10)),
Taeheon Kim ([**@lonyele**](https://github.com/lonyele)),
Tom Parker-Shemilt ([**@palfrey**](https://github.com/palfrey)),
Try Ajitiono ([**@imballinst**](https://github.com/imballinst)),
Yamagishi Kazutoshi ([**@ykzts**](https://github.com/ykzts)),
Yoav Kadosh ([**@ykadosh**](https://github.com/ykadosh)),
Yordis Prieto ([**@Yordis**](https://github.com/Yordis)),
Adrian Foong ([**@adrfoong**](https://github.com/adrfoong)),
Dan Abramov ([**@gaearon**](https://github.com/gaearon)),
[**@ihupoo**](https://github.com/ihupoo),
[**@nikhog**](https://github.com/nikhog),
[**@redallen**](https://github.com/redallen),
Akshay Kadam ([**@deadcoder0904**](https://github.com/deadcoder0904)),
я котик пур-пур ([**@mvasilkov**](https://github.com/mvasilkov)),
Anders D. Johnson ([**@AndersDJohnson**](https://github.com/AndersDJohnson)),
Andrew Aylett ([**@andrewaylett**](https://github.com/andrewaylett)),
Ankeet Maini ([**@ankeetmaini**](https://github.com/ankeetmaini)),
Biswas Nandamuri ([**@Biswas-N**](https://github.com/Biswas-N)),
Bret ([**@bcomnes**](https://github.com/bcomnes)),
Chris Chinchilla ([**@ChrisChinchilla**](https://github.com/ChrisChinchilla)),
Christopher Biscardi ([**@ChristopherBiscardi**](https://github.com/ChristopherBiscardi)),
Dan Overton ([**@dan-overton**](https://github.com/dan-overton)),
Domitrius ([**@domitriusclark**](https://github.com/domitriusclark)),
Dovi Winberger ([**@dowi**](https://github.com/dowi)),
Emmie Päivärinta ([**@emmiep**](https://github.com/emmiep)),
Eugene Ghanizadeh ([**@loreanvictor**](https://github.com/loreanvictor)),
and anyone we may have forgotten.

[architecture]: /packages/mdx/#architecture

[contribute]: /community/contribute/

[extending]: /docs/extending-mdx/

[getting-started]: /docs/getting-started/

[jsx-runtime]: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

[micromark]: https://github.com/micromark/micromark

[migrating]: /migrating/v2/

[packages]: /packages/

[rsc]: https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html

[ts]: /docs/getting-started/#types

[types-mdx]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mdx

[typescript]: https://www.typescriptlang.org

[unified]: https://unifiedjs.com

[what]: /docs/what-is-mdx/


================================================
FILE: docs/blog/v3.mdx
================================================
import {Note} from '../_component/note.jsx'
export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2023-10-24')
}

<Note type="info">
  **Note**: Info on how to migrate is available in our
  [Version 3 migration guide][migrating].
</Note>

# MDX 3

Version 3 already!
This major version contains a couple small changes.
For most folks, updating Node.js and plugins is all that’s needed!

{/* more */}

## Contents

* [Breaking changes](#breaking-changes)
* [Improvements to the MDX format](#improvements-to-the-mdx-format)
  * [Adjacent block JSX and expressions in MDX](#adjacent-block-jsx-and-expressions-in-mdx)
  * [Await in MDX](#await-in-mdx)
  * [ES2024 in MDX](#es2024-in-mdx)
* [Miscellaneous](#miscellaneous)
* [Thanks](#thanks)

## Breaking changes

The main breaking change is that Node.js 16 is now the minimum supported
version.

Across the ecosystem there were several small internal breaking changes.
Everything’s released already.
You can update all plugins now.
If you ran into problems before, it should work now.

We also removed some infrequently used deprecated APIs.
You’re likely fine but gloss over the [v3 migration guide][migrating] if you
get errors.

Important to note when you use your lesser-known but powerful `evaluate`, `run`,
or `outputFormat: 'function-body'` APIs, please pass the `baseUrl` option.
That makes sure `import.meta.url`, `import`, and `export` work.
You’ll get a runtime error when those features are used otherwise.

## Improvements to the MDX format

There’s also a few small improvements to the MDX format, some of which
technically breaking.

### Adjacent block JSX and expressions in MDX

We now accept block expressions right next to block JSX tags:

```mdx chrome=no
<style>{`

  h1 {
    color: blue;
  }

`}</style>
```

Previously, there was a syntax error, and you had to add a newline between the
angle brackets and the braces.

### Await in MDX

We now accept `await` syntax:

```mdx
{await Promise.resolve(42)}
```

Most frameworks don’t support promises.
Whether this works depends on that.

Previously, there was a runtime error that `await` was used in a context where
it wasn’t allowed.

### ES2024 in MDX

You can now use modern JavaScript syntax in MDX.
Acorn, used internally, is now instructed to use ES2024.

## Miscellaneous

I refactored all the docs.
Updating every use example where needed.
I also wrote a guide on how to inject components from anywhere:
[§ Injecting components][injecting-components].

The site is a lot faster.
There’s a nice improved playground too: [try it out! »][playground].
We also have proper syntax highlighting here, thanks to
[`wooorm/markdown-tm-language`][markdown-tm-language]
and [`wooorm/starry-night`][starry-night].

The generated JS code is a little cleaner (the JSX pragma comment is removed
and objects are sorted where needed), it also uses spreads instead of
`Object.assign`, there’s a `'use strict'` added when needed, and the
`MDXContent` is exported immediately.

## Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
北雁云依 ([**@BeiyanYunyi**](https://github.com/BeiyanYunyi)),
Christian Murphy ([**@ChristianMurphy**](https://github.com/ChristianMurphy)),
JokcyLou ([**@Jokcy**](https://github.com/Jokcy)),
Maël Nison ([**@arcanis**](https://github.com/arcanis)),
Andreas Deininger ([**@deining**](https://github.com/deining)),
Remco Haszing ([**@remcohaszing**](https://github.com/remcohaszing)),
Sébastien Lorber ([**@slorber**](https://github.com/slorber)),
Víctor Fernández ([**@victor23k**](https://github.com/victor23k)),
Titus Wormer ([**@wooorm**](https://github.com/wooorm)),
and anyone we may have forgotten.

[injecting-components]: /guides/injecting-components/

[markdown-tm-language]: https://github.com/wooorm/markdown-tm-language

[migrating]: /migrating/v3/

[playground]: /playground/

[starry-night]: https://github.com/wooorm/starry-night


================================================
FILE: docs/community/about.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-06')
}
export const navSortSelf = 4

# About

This article explains in short how MDX came to be and why it exists.
It also gives thanks to the people who’ve helped make it and inspired it.

{/* more */}

## What is MDX?

MDX is the combination of markdown with JSX.
See [§ What is MDX?][what] for more info.

## Why MDX?

Markdown does not have a syntax for custom components.
MDX solves this.

There are many languages objectively better than markdown, however, markdown is
great because:

* It looks like what it means and is relatively easy to read
* Although images are [confusing][], most stuff is relatively simple to write
* It’s loose and ambiguous: it may not work but you won’t get an error (great
  for someone posting a comment to a forum if they forgot an asterisk)

Markdown *does* have a way to extend it, HTML, but that has drawbacks:

* HTML in markdown is naïve, how it’s parsed sometimes doesn’t make sense
* HTML is unsafe by default, so it’s sometimes (partially) unsupported
* HTML and markdown don’t mix well, resulting in confusing rules such as
  blank lines or `markdown="1"` attributes
* HTML is coupled with browsers, markdown is useful for other things too

The frontend world has an alternative to HTML: JSX.
JSX is great, amongst other things, because:

* It has a relatively familiar syntax (like XML)
* It’s agnostic to semantics and intended for compilers (can have any
  domain-specific meaning)
* It’s strict and unambiguous (great if an author forgot a slash somewhere, as
  they’ll get an error early, instead of a book going to print with broken
  stuff in it)

## Who governs MDX?

The project is governed by the
[unified collective][governance].

## Who created MDX?

The idea of combining [markdown][commonmark], [JavaScript][], and [JSX][] was a
collaborative effort by
[Guillermo Rauch][mdx-rauchg] (**[@rauchg][rauchg]**),
[James K. Nelson][mdx-jamesknelson] (**[@jamesknelson][jamesknelson]**),
[John Otander][mdx-johno] (**[@johno][johno]**),
Tim Neutkens (**[@timneutkens][timneutkens]**),
Brent Jackson (**[@jxnblk][jxnblk]**),
Jessica Stokes (**[@ticky][ticky]**), and more.

While everyone above was key to MDX, we want to stress the involvement of
[John Otander][mdx-johno] (**[@johno][johno]**).
John wrote most of the code for the first alpha and later stable version 1 of
this project!

## Who designed the logo?

[Logo designs][design] were created by [Evil Rabbit][] of [Vercel][].

## What projects inspired MDX?

The following projects, languages, and articles helped shape MDX either in
implementation or inspiration.

The [markdown][] and [JSX][] languages inspired MDX.
Markdown was [created by John Gruber][markdown] (**[@gruber][gruber]**).
[CommonMark][], the most popular markdown variant, by John McFarlane
(**[@jgm][jgm]**) et al.
JSX was created by Sebastian Markbåge (**[@sebmarkbage][sebmarkbage]**) et
al. at Facebook, Inc.

The `@mdx-js/*` projects currently make heavy use of [unified][] (specifically
[micromark][], [remark][] and [rehype][]) and [Acorn][].
unified, remark, rehype, and related tools were created by Titus Wormer
(**[@wooorm][wooorm]**) et al.
Acorn by Marijn Haverbeke (**[@marijnh][marijnh]**) et al.

The following projects inspired `@mdx-js/*` originally:

{/* Note: please keep the original project names intact: */}

* [`jamesknelson/mdxc`](https://github.com/frontarm/mdx-util)
* [`ticky/markdown-component-loader`](https://github.com/ticky/markdown-component-loader)
* [`threepointone/markdown-in-js`](https://github.com/threepointone/markdown-in-js)
* [`fazouane-marouane/remark-jsx`](https://github.com/remarkjs/remark-jsx)
* [`mapbox/remark-react`](https://github.com/remarkjs/remark-react)
* [`rx-ts/eslint-mdx`](https://github.com/mdx-js/eslint-mdx)

The following articles inspired `@mdx-js/*` originally:

* [IA Markdown Content Blocks](https://github.com/iainc/Markdown-Content-Blocks)
* [Idyll: Markup language for interactive documents](https://idyll-lang.org)

[acorn]: https://github.com/acornjs/acorn

[commonmark]: https://spec.commonmark.org/current/

[confusing]: https://twitter.com/gruber/status/1246489863932821512

[design]: https://github.com/mdx-js/design

[evil rabbit]: https://evilrabb.it

[governance]: https://github.com/unifiedjs/collective

[gruber]: https://github.com/gruber

[jamesknelson]: https://github.com/jamesknelson

[javascript]: https://tc39.es/ecma262/

[jgm]: https://github.com/jgm

[johno]: https://github.com/johno

[jsx]: https://facebook.github.io/jsx/

[jxnblk]: https://github.com/jxnblk

[marijnh]: https://github.com/marijnh

[markdown]: https://daringfireball.net/2004/03/introducing_markdown

[mdx-jamesknelson]: https://github.com/frontarm/mdx-util/tree/0f5f6d62bac4b83edc4bc3890dde3011079fa318

[mdx-johno]: https://github.com/mdx-js/mdx/tree/a96ede2c104084ae21efa8bd95319011e558ec9d

[mdx-rauchg]: https://spectrum.chat/frontend/general/mdx-proposal~1021be59-2738-4511-aceb-c66921050b9a

[micromark]: https://github.com/micromark/micromark

[rauchg]: https://github.com/rauchg

[rehype]: https://github.com/rehypejs/rehype

[remark]: https://github.com/remarkjs/remark

[sebmarkbage]: https://github.com/sebmarkbage

[ticky]: https://github.com/ticky

[timneutkens]: https://github.com/timneutkens

[unified]: https://unifiedjs.com

[vercel]: https://vercel.com

[what]: /docs/what-is-mdx/

[wooorm]: https://github.com/wooorm


================================================
FILE: docs/community/contribute.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2018-11-04')
}
export const navSortSelf = 2

# Contribute

This article explains how to contribute to MDX.
Please read through the following guidelines.

{/* more */}

<Note type="important">
  **Important**: before participating in our community, please read our
  [code of conduct][coc].
  By interacting with this repository, organization, or community you agree to
  abide by its terms.
</Note>

## Contributions

There’s several ways to contribute, not just by writing code.
If you have questions, see [§ Support][support].
If you can provide financial support, see [§ Sponsor][sponsor].

### Improve docs

As a user you’re perfect for helping us improve our docs.
Typo corrections, error fixes, better explanations, new examples, etcetera.
All MDX docs live in `docs/`.

You can run the docs locally, see [¶ Site][site] below.

### Improve issues

Some issues lack information, aren’t reproducible, or are just incorrect.
You can help by trying to make them easier to resolve.
Existing issues might benefit from your unique experience or opinions.

### Write code

Code contributions are very welcome.
It’s probably a good idea to first post a question or open an issue to report a
bug or suggest a new feature before creating a pull request.

## Submitting an issue

* The issue tracker is for issues.
  Use discussions for support
* Search the issue tracker (including closed issues) before opening a new
  issue
* Ensure you’re using the latest version of our packages
* Use a clear and descriptive title
* Include as much information as possible: steps to reproduce the issue,
  error message, version, operating system, etcetera
* The more time you put into an issue, the better we will be able to help you
* The best issue report is a failing test proving it

## Submitting a pull request

* See [¶ Project][project] below for info on how the project is structured,
  how to test, and how to build the site
* Non-trivial changes are often best discussed in an issue first, to prevent
  you from doing unnecessary work
* For ambitious tasks, you should try to get your work in front of the
  community for feedback as soon as possible
* New features should be accompanied by tests and documentation
* Don’t include unrelated changes
* Test before submitting code by running `npm test`
* Write a convincing description of why we should land your pull request:
  it’s your job to convince us

## Project

### Structure

MDX is a monorepo.
All packages are in `packages/`.
Documentation is in `docs/`.

### Tests

To run the tests, first do `npm install`, then do `npm test`.
This ensures everything is okay, from code style to unit tests to types.

### Site

To build the site, first do `npm install`, then do `npm run docs`.
This produces the website in `public/`.

### Release

To release a new version, do:

1. update `version`s of packages with a patch, minor, or major (make sure to
   update dependency ranges on monorepo packages when needed):
   ```sh
   npm version minor --workspaces --no-git-tag-version
   ```
2. commit and tag using the version (without `v`) as the message:
   ```sh
   git commit --all --message 1.2.3 && git tag 1.2.3 && git push && git push --tags
   ```
3. release to the npm registry:
   ```sh
   npm publish --workspaces
   ```
4. add a changelog entry for the release on GitHub:
   ```sh
   open https://github.com/mdx-js/mdx/releases
   ```

## Resources

* [Good first issues in the MDX repository](https://github.com/mdx-js/mdx/labels/good%20first%20issue%20👋)
* [How to contribute to open source](https://opensource.guide/how-to-contribute/)
* [Making your first contribution](https://medium.com/@vadimdemedes/making-your-first-contribution-de6576ddb190)
* [Using pull requests](https://help.github.com/articles/about-pull-requests/)
* [GitHub help](https://help.github.com)

[coc]: https://github.com/mdx-js/.github/blob/main/code-of-conduct.md

[project]: #project

[site]: #site

[sponsor]: /community/sponsor/

[support]: /community/support/


================================================
FILE: docs/community/index.mdx
================================================
{
  /**
   * @import {Item} from '../_component/sort.js'
   */

  /**
   * @typedef Props
   * @property {Item} navigationTree
   */
}

import assert from 'node:assert/strict'
import {NavigationGroup} from '../_component/nav.jsx'

export const info = {
  author: [{name: 'MDX Contributors'}],
  modified: new Date('2024-07-04'),
  published: new Date('2021-11-01')
}
export const navSortSelf = 6

# Community

These pages explain how to contribute, get help, sponsor us, share your work,
and some background information.

{
  (function () {
    const navigationTree = props.navigationTree
    const category = navigationTree.children.find(function (item) {
      return item.name === '/community/'
    })
    assert(category)

    return (
      <nav>
        <NavigationGroup items={category.children} includeDescription />
      </nav>
    )
  })()
}


================================================
FILE: docs/community/projects.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'johno', name: 'John Otander'}
  ],
  modified: new Date('2021-11-01'),
  published: new Date('2018-08-11')
}
export const navSortSelf = 5

# Projects

<Note type="info">
  **Note**: have another project built with MDX?
  Please send a PR to add it here!
</Note>

This page lists community projects using MDX.

{/* more */}

## Apps

* [demoboard][]: The simplest editor alive

## Libraries

* [ok-mdx][]: Browser-based MDX editor
* [docz][]: Documentation framework
* [mdx-deck][]: MDX-based presentation decks
* [mdx-docs][]: Next-based documentation framework
* [mdx-paper][]: MDX-based research articles
* [spectacle-boilerplate-mdx][]: Boilerplate that facilitates using MDX with
  Spectacle
* [Charge][]: An opinionated, zero-config static site generator
* [MDNEXT][]: An ecosystem of tools to get your NextJS + MDX projects blasting
  off

## Sites

* This website!
* [Prisma][]
* [Max Stoiber’s Blog][mxstbr]

## Other related links

* [awesome-mdx][]
* [MDX: content for kings and princesses][mdx-fairy-tale]

[awesome-mdx]: https://github.com/transitive-bullshit/awesome-mdx

[charge]: https://charge.js.org

[demoboard]: https://frontarm.com/demoboard

[docz]: https://www.docz.site/

[mdnext]: https://github.com/domitriusclark/mdnext

[mdx-deck]: https://github.com/jxnblk/mdx-deck

[mdx-docs]: https://github.com/jxnblk/mdx-docs

[mdx-fairy-tale]: https://github.com/DeveloperMode/mdx-fairy-tale

[mdx-paper]: https://github.com/hubgit/mdx-paper

[mxstbr]: https://mxstbr.com

[ok-mdx]: https://github.com/jxnblk/ok-mdx

[prisma]: https://www.prisma.io/docs

[spectacle-boilerplate-mdx]: https://github.com/FormidableLabs/spectacle-boilerplate-mdx


================================================
FILE: docs/community/sponsor.mdx
================================================
export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-06'),
}
export const navSortSelf = 3

# Sponsor

This article explains how to contribute financially to MDX.

{/* more */}

It’s possible to support us financially by becoming a backer or sponsor of
unified through either [Open Collective][oc] or [GitHub Sponsors][gh].
With this support, we can pay for project leadership, finance non-coding work,
or for fun things for the community like getting stickers for contributors.
You’ll be helping unified’s maintainers manage and improve existing projects,
and additionally support our work to develop new and exciting projects, such
as [micromark][].

{
  <table>
    <tr valign="middle">
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://vercel.com" rel="sponsored nofollow">Vercel</a><br /><br />
        <a href="https://vercel.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/14985020?s=256&v=4" width="128" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://motif.land" rel="sponsored nofollow">Motif</a><br /><br />
        <a href="https://motif.land" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/74457950?s=256&v=4" width="128" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://www.hashicorp.com" rel="sponsored nofollow">HashiCorp</a><br /><br />
        <a href="https://www.hashicorp.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/761456?s=256&v=4" width="128" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://www.gitbook.com" rel="sponsored nofollow">GitBook</a><br /><br />
        <a href="https://www.gitbook.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/7111340?s=256&v=4" width="128" /></a>
      </td>
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://www.gatsbyjs.org" rel="sponsored nofollow">Gatsby</a><br /><br />
        <a href="https://www.gatsbyjs.org" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/12551863?s=256&v=4" width="128" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
    </tr>
    <tr valign="middle" />
    <tr valign="middle">
      <td width="20%" align="center" rowSpan={2} colSpan={2}>
        <a href="https://www.netlify.com" rel="sponsored nofollow">Netlify</a><br /><br />
        {/* OC has a sharper image */}
        <a href="https://www.netlify.com" rel="sponsored nofollow"><img src="https://images.opencollective.com/netlify/4087de2/logo/256.png" width="128" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://www.coinbase.com" rel="sponsored nofollow">Coinbase</a><br /><br />
        <a href="https://www.coinbase.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/1885080?s=256&v=4" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://themeisle.com" rel="sponsored nofollow">ThemeIsle</a><br /><br />
        <a href="https://themeisle.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/58979018?s=128&v=4" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://expo.io" rel="sponsored nofollow">Expo</a><br /><br />
        <a href="https://expo.io" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/12504344?s=128&v=4" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://boostnote.io" rel="sponsored nofollow">Boost Note</a><br /><br />
        <a href="https://boostnote.io" rel="sponsored nofollow"><img src="https://images.opencollective.com/boosthub/6318083/logo/128.png" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://markdown.space" rel="sponsored nofollow">Markdown Space</a><br /><br />
        <a href="https://markdown.space" rel="sponsored nofollow"><img src="https://images.opencollective.com/markdown-space/e1038ed/logo/128.png" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" align="center">
        <a href="https://www.holloway.com" rel="sponsored nofollow">Holloway</a><br /><br />
        <a href="https://www.holloway.com" rel="sponsored nofollow"><img src="https://avatars1.githubusercontent.com/u/35904294?s=128&v=4" width="64" style={{display: 'block', maxWidth: '100%'}} /></a>
      </td>
      <td width="10%" />
      <td width="10%" />
    </tr>
    <tr valign="middle">
      <td width="100%" align="center" colSpan={8}>
        <br />
        <a href="https://opencollective.com/unified"><strong>You?</strong></a>
        <br /><br />
      </td>
    </tr>
  </table>
}

[gh]: https://github.com/sponsors/unifiedjs

[micromark]: https://github.com/micromark/micromark

[oc]: https://opencollective.com/unified


================================================
FILE: docs/community/support.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2019-07-03')
}
export const navSortSelf = 1

# Support

This article explains where to get help with MDX.
Please read through the following guidelines.

{/* more */}

<Note type="important">
  **Important**: before participating in our community, please read our
  [code of conduct][coc].
  By interacting with this repository, organization, or community you agree to
  abide by its terms.
</Note>

## Asking quality questions

Questions can go to [GitHub Discussions][chat].

Help us help you!
Spend time framing questions and add links and resources.
Spending the extra time up front can help save everyone time in the long run.
Here are some tips:

* Read through [§ Getting started][getting-started]
* [Talk to a duck!][rubberduck]
* Don’t fall for the [XY problem][xy]
* Search to find out if a similar question has been asked
* Try to define what you need help with:
  * Is there something in particular you want?
  * What problem are you encountering and what steps have you taken to try
    and fix it?
  * Is there a concept you don’t understand?
* Provide sample code, such as a [CodeSandbox][cs] or video, if possible
* Screenshots can help, but if there’s important text such as code or error
  messages in them, please also provide those as text
* The more time you put into asking your question, the better we can help you

[chat]: https://github.com/mdx-js/mdx/discussions

[coc]: https://github.com/mdx-js/.github/blob/main/code-of-conduct.md

[cs]: https://codesandbox.io

[getting-started]: /docs/getting-started/

[rubberduck]: https://rubberduckdebugging.com

[xy]: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/66378#66378


================================================
FILE: docs/docs/extending-mdx.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-06')
}
export const navSortSelf = 4

# Extending MDX

This article explains how to extend MDX content—specifically, how to *transform*
content with plugins. {/* more */}
See [§ Using MDX][use] for how to pass components, props, and the layout.
See [§ Getting started][start] for how to integrate MDX into your project.

## Contents

* [Components & plugins](#components--plugins)
  * [List of components](#list-of-components)
  * [List of plugins](#list-of-plugins)
* [Using plugins](#using-plugins)
* [Creating plugins](#creating-plugins)

## Components & plugins

There are three extension points when using `@mdx-js/mdx` or one of its
integrations:

* Options passed to the compiler (see [¶ API in `@mdx-js/mdx`][api])
* Plugins that hook into several stages of compilation (see [remark
  plugins][remark-plugins], [rehype plugins][rehype-plugins], and
  [recma plugins][recma-plugins])
* Components passed, defined, or imported at runtime (see [§ Using MDX][use])

Most of the time, these components and plugins are not coupled to MDX.
For example, if you’re using React, then you can use
[`<ReactConfetti />`][react-confetti] with MDX.
Or, you can use the plugin [`remark-gfm`][remark-gfm] to turn on GFM features in
MDX.
Sometimes, we need specific components or specific plugins to work with MDX.
We’re compiling those here on this page.

### List of components

* [`PaulieScanlon/mdx-embed`](https://github.com/PaulieScanlon/mdx-embed)
  — React components for embedding 3rd party content, integrates w/
  MDX provider
* [`system-ui/theme-ui`](https://github.com/system-ui/theme-ui)
  — React components for building consistent apps, integrates w/ MDX provider

{/*
  * Please use alpha sorting on **project** name!
  * You can use this template:
  *
  * ```markdown
  * * [`user/project`](https://github.com/user/project)
  *   — somewhat short description of the project
  * ```
  */}

<Note type="info">
  **Note**: have another component that *specifically* works with MDX?
  Please send a PR to add it here!
</Note>

### List of plugins

See also the [list of remark plugins][remark-plugins],
[list of rehype plugins][rehype-plugins], and
[list of recma plugins][recma-plugins].

* [`remcohaszing/recma-export-filepath`](https://github.com/remcohaszing/recma-export-filepath)
  — export the filepath
* [`ipikuka/recma-mdx-change-props`](https://github.com/ipikuka/recma-mdx-change-props)
  — changes the param as `_props` in the `_createMdxContent` function
* [`domdomegg/recma-mdx-displayname`](https://github.com/domdomegg/recma-mdx-displayname)
  — add a `displayName` to `MDXContent` components, to enable switching
  on them in production
* [`ipikuka/recma-mdx-escape-missing-components`](https://github.com/ipikuka/recma-mdx-escape-missing-components)
  — set a default value of `() => null` for missing components instead of
  throwing an error
* [`remcohaszing/recma-mdx-is-mdx-component`](https://github.com/remcohaszing/recma-mdx-is-mdx-component)
  — add an `isMdxComponent` field on MDX components
* [`remcohaszing/recma-nextjs-static-props`](https://github.com/remcohaszing/recma-nextjs-static-props)
  — generate [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
  exposing top level identifiers in Next.js
* [`remcohaszing/recma-module-to-function`](https://github.com/remcohaszing/recma-module-to-function)
  — convert a module into a function body
* [`remcohaszing/rehype-mdx-code-props`](https://github.com/remcohaszing/rehype-mdx-code-props)
  — interpret the code `meta` field as JSX props
* [`remcohaszing/rehype-mdx-import-media`](https://github.com/remcohaszing/rehype-mdx-import-media)
  — change media sources to JavaScript imports
* [`remcohaszing/rehype-mdx-title`](https://github.com/remcohaszing/rehype-mdx-title)
  — expose the page title as a string
* [`boning-w/rehype-mdx-toc`](https://github.com/boning-w/rehype-mdx-toc)
  — export the table of contents data into MDX module
* [`re-xyr/remark-directive-mdx`](https://github.com/re-xyr/remark-directive-mdx)
  — transform Markdown directives (`:directive[]`) to JSX elements
* [`pangelani/remark-mdx-chartjs`](https://github.com/pangelani/remark-mdx-chartjs)
  — replace fenced code blocks with charts using [`react-chartjs-2`](https://react-chartjs-2.js.org/).
* [`remcohaszing/remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter)
  — change frontmatter (YAML) metadata to exports
* [`goodproblems/remark-mdx-math-enhanced`](https://github.com/goodproblems/remark-mdx-math-enhanced)
  — enhance math with JavaScript inside it

{/*
  * Please use alpha sorting on **project** name!
  * You can use this template:
  *
  * ```markdown
  * * [`user/project`](https://github.com/user/project)
  *   — somewhat short description of the project
  * ```
  */}

<Note type="info">
  **Note**: have another unified plugin that *specifically* works with MDX?
  Please send a PR to add it here!
</Note>

## Using plugins

Where to pass plugins is encoded in their name:
remark plugins go in `remarkPlugins`,
rehype plugins go in `rehypePlugins`,
and recma plugins go in `recmaPlugins` of
[`ProcessorOptions`][processor-options].
Those fields expect lists of plugins and/or of `[plugin, options]`:

```tsx twoslash
import {compile} from '@mdx-js/mdx'
import rehypeKatex from 'rehype-katex' // Render math with KaTeX.
import remarkFrontmatter from 'remark-frontmatter' // YAML and such.
import remarkGfm from 'remark-gfm' // Tables, footnotes, strikethrough, task lists, literal URLs.
import remarkMath from 'remark-math' // Support math like `$so$`.

const file = '# hi'

// One plugin:
await compile(file, {remarkPlugins: [remarkGfm]})

// A plugin with options:
await compile(file, {remarkPlugins: [[remarkFrontmatter, 'toml']]})

// Two plugins:
await compile(file, {remarkPlugins: [remarkGfm, remarkFrontmatter]})

// Two plugins, first w/ options:
await compile(file, {remarkPlugins: [[remarkGfm, {singleTilde: false}], remarkFrontmatter]})

// remark and rehype plugins:
await compile(file, {rehypePlugins: [rehypeKatex], remarkPlugins: [remarkMath]})

// remark and rehype plugins, last w/ options:
await compile(file, {
  // A plugin with options:
  rehypePlugins: [[rehypeKatex, {strict: true, throwOnError: true}]],
  remarkPlugins: [remarkMath]
})
```

## Creating plugins

Creating a plugin for MDX is mostly the same as creating a plugin for remark,
rehype, or recma.
There are several guides and recipes on that in [§ Learn on
`unifiedjs.com`][learn].

For the MDX specific parts of plugins, it’s recommended to read
[¶ Architecture][architecture] to learn how `@mdx-js/mdx` works.
For info on the node types that represent MDX specific features, see
[¶ Syntax tree in `remark-mdx`][syntax-tree] and use our interactive
[§ Playground][playground].

[api]: /packages/mdx/#api

[architecture]: /packages/mdx/#architecture

[learn]: https://unifiedjs.com/learn/

[playground]: /playground/

[processor-options]: /packages/mdx/#processoroptions

[react-confetti]: https://github.com/alampros/react-confetti

[recma-plugins]: https://github.com/mdx-js/recma/blob/main/doc/plugins.md#list-of-plugins

[rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins

[remark-gfm]: https://github.com/remarkjs/remark-gfm

[remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins

[start]: /docs/getting-started/

[syntax-tree]: /packages/remark-mdx/#syntax-tree

[use]: /docs/using-mdx/


================================================
FILE: docs/docs/getting-started.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-05')
}
export const navSortSelf = 2

# 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. {/* more */}
To understand how the MDX format works,
we recommend that you start with [§ What is MDX][what].
See [§ Using MDX][use] when you’re all set up and ready to use MDX.

## Contents

* [Prerequisites](#prerequisites)
* [Quick start](#quick-start)
  * [Bundler](#bundler)
  * [JSX](#jsx)
  * [Editor](#editor)
  * [Types](#types)
  * [Security](#security)
* [Integrations](#integrations)
  * [Bundlers](#bundlers)
  * [Build systems](#build-systems)
  * [Linters](#linters)
  * [Compilers](#compilers)
  * [Site generators](#site-generators)
  * [JSX runtimes](#jsx-runtimes)
  * [JavaScript engines](#javascript-engines)
* [Further reading](#further-reading)

## 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][node-js] version of 16 or later is needed to use them.
Our packages are also [ESM only][github-gist-esm].

<Note type="info">
  **Note**: Using Rust instead of Node.js?
  Try [`mdxjs-rs`][mdxjs-rs]!
</Note>

## 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`][mdx-esbuild]
* if you use **Rollup** (or Vite),
  install and configure [`@mdx-js/rollup`][mdx-rollup]
* if you use **webpack** (or Next.js),
  install and configure [`@mdx-js/loader`][mdx-loader]

You can also use MDX without bundlers:

* you can import MDX files in **Node.js** with
  [`@mdx-js/node-loader`][mdx-node-loader]
* you can use our core compiler [`@mdx-js/mdx`][mdx-mdx] to compile MDX files
* you can use our core compiler [`@mdx-js/mdx`][mdx-mdx] to
  [evaluate][api-evaluate] (compile *and run*) MDX files

For more info on these tools,
see their dedicated sections:
[¶ Next.js][site-generator-next],
[¶ Node.js][js-engine-node],
[¶ Rollup][bundler-rollup],
[¶ Vite][build-system-vite],
[¶ esbuild][bundler-esbuild], and
[¶ webpack][bundler-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`][mdx-react]
* if you use **Preact**,
  set [`jsxImportSource` in `ProcessorOptions`][api-processor-options] to
  `'preact'`;
  optionally install and configure [`@mdx-js/preact`][mdx-preact]
* if you use **Svelte**,
  install [`svelte-jsx`][svelte-jsx],
  and set [`jsxImportSource` in `ProcessorOptions`][api-processor-options] to
  `'svelte-jsx'`
* if you use **Vue**,
  set [`jsxImportSource` in `ProcessorOptions`][api-processor-options] to
  `'vue'`;
  optionally install and configure [`@mdx-js/vue`][mdx-vue]
* if you use **Solid**,
  set [`jsxImportSource` in `ProcessorOptions`][api-processor-options] to
  `'solid-js/h'`
* if you use **Emotion**,
  set [`jsxImportSource` in `ProcessorOptions`][api-processor-options] to
  `'@emotion/react'`
* if you use **Theme UI**,
  install and configure [`@mdx-js/react`][mdx-react],
  then wrap your MDX content in a `<ThemeProvider />`

Other JSX runtimes are supported by setting
[`jsxImportSource` in `ProcessorOptions`][api-processor-options].

For more info on these tools,
see their dedicated sections:
[¶ Emotion][jsx-runtime-emotion],
[¶ Preact][jsx-runtime-preact],
[¶ React][jsx-runtime-react],
[¶ Solid][jsx-runtime-solid],
[¶ Svelte][jsx-runtime-svelte],
[¶ Theme UI][jsx-runtime-theme-ui], and
[¶ Vue][jsx-runtime-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`][mdx-analyzer]
* if you use **Vim**,
  try [`jxnblk/vim-mdx-js`][vim-mdx-js]
* if you use **Sublime Text**,
  try [`jonsuh/mdx-sublime`][mdx-sublime]
* if you use **JetBrains IntelliJ/WebStorm**,
  try [`JetBrains/mdx-intellij-plugin`][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`][markdown-tm-language].

### Types

<details>
  <summary>Expand example of typed imports</summary>

  First install the package:

  ```sh
  npm install @types/mdx
  ```

  …TypeScript should automatically pick it up:

  ```js twoslash path="example.js"
  // @filename: types.d.ts
  import type {} from 'mdx'
  // @filename: example.js
  // ---cut---
  import Post from './post.mdx' // `Post` is now typed.
  ```
</details>

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`][definitely-typed-react],
then augmenting the `mdx/types.js` module.

```ts twoslash path="example.ts"
import * as React from 'react'

declare module 'mdx/types.js' {
  export import JSX = React.JSX
}
```

To enable types for imported `.mdx`, `.md`, etc.,
install and use [`@types/mdx`][definitely-typed-mdx].
This package also exports several useful types,
such as `MDXComponents` which represents the `components` prop.
You can import them like so:

```ts twoslash path="example.ts"
import type {MDXComponents} from 'mdx/types.js'
```

### 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

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  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… */})]
  })
  ```
</details>

We support [esbuild][].
Install and configure the esbuild plugin [`@mdx-js/esbuild`][mdx-esbuild].
[Configure your JSX runtime][jsx] 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`][esbuild-target].

See also [¶ Bun][javascript-engines-bun],
which you might be using,
for more info.

#### Rollup

<details>
  <summary>Expand example</summary>

  ```js twoslash path="rollup.config.js"
  /**
   * @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
  ```
</details>

We support [Rollup][].
Install and configure the Rollup plugin [`@mdx-js/rollup`][mdx-rollup].
[Configure your JSX runtime][jsx] 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`][mdx-rollup-babel].

See also [¶ Vite][build-system-vite],
if you use Rollup through it,
for more info.

#### Webpack

<details>
  <summary>Expand example</summary>

  ```js twoslash path="webpack.config.js"
  /**
   * @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
  ```
</details>

We support [webpack][].
Install and configure the webpack loader [`@mdx-js/loader`][mdx-loader].
[Configure your JSX runtime][jsx] 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`][mdx-loader-babel].

See also [¶ Next.js][site-generator-next],
if you use webpack through it,
for more info.

### Build systems

#### Vite

<details>
  <summary>Expand example</summary>

  ```js twoslash path="vite.config.js"
  import mdx from '@mdx-js/rollup'
  import {defineConfig} from 'vite'

  const viteConfig = defineConfig({
    plugins: [
      mdx(/* jsxImportSource: …, otherOptions… */)
    ]
  })

  export default viteConfig
  ```
</details>

We support [Vite][].
Install and configure the Rollup plugin [`@mdx-js/rollup`][mdx-rollup].
[Configure your JSX runtime][jsx] 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`][vite-build-target].

<Note type="info">
  **Note**: If you also use `@vitejs/plugin-react`,
  you must force `@mdx-js/rollup` to run in the `pre` phase before it:

  ```js twoslash path="vite.config.js"
  import mdx from '@mdx-js/rollup'
  import react from '@vitejs/plugin-react'
  import {defineConfig} from 'vite'
  // ---cut---
  // …
  const viteConfig = defineConfig({
    plugins: [
      {enforce: 'pre', ...mdx({/* jsxImportSource: …, otherOptions… */})},
      react({include: /\.(jsx|js|mdx|md|tsx|ts)$/})
    ]
  })
  // …
  ```
</Note>

See also [¶ Rollup][bundler-rollup] which is used in Vite and see
[¶ Vue][jsx-runtime-vue] if you’re using that,
for more info.

### Linters

#### ESLint

You can lint your MDX code with [ESLint][] using [`eslint-mdx`][eslint-mdx].

#### mdxlint

You can lint your MDX code with [`remark-lint`][remark-lint] and other
[remark plugins][] using [`mdxlint`][mdxlint].

### Compilers

#### Babel

<details>
  <summary>Expand plugin and sample use</summary>

  This plugin:

  ```js twoslash path="plugin.js"
  /**
   * @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)
    }
  }
  ```

  …can be used like so with the Babel API:

  ```js twoslash path="example.js"
  /// <reference types="node" />
  // ---cut---
  // @filename: plugin.js
  /**
   * @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 types are wrong.
    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)
    }
  }
  // @filename: example.js
  // ---cut---
  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)
  ```
</details>

You 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][astro-framework-components] 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][astro-mdx].

#### Docusaurus

[Docusaurus][] supports MDX by default.
See [Docusaurus’ MDX and React guide][docusaurus-markdown-react] for info on
how to use MDX with Docusaurus.

#### Gatsby

[Gatsby][] has its own plugin to support MDX.
See [`gatsby-plugin-mdx`][gatsby-plugin-mdx] on how to use MDX with Gatsby.

#### Next.js

<details>
  <summary>Expand example</summary>

  ```js twoslash path="next.config.js"
  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
  ```
</details>

[Next.js][next] has its own MDX integration.
Install and configure [`@next/mdx`][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`][next-configuring-mdx] for more info.

#### Parcel

[Parcel][] has its own plugin to support MDX.
See [`@parcel/transformer-mdx`][parcel-mdx]
on how to use MDX with Parcel.

<Note type="info">
  **Note**: the official Parcel plugin is currently not maintained.
  For a maintained alternative,
  try [`parcel-transformer-mdx`][parcel-transformer-mdx].
</Note>

### JSX runtimes

#### Emotion

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  import {compile} from '@mdx-js/mdx'

  const js = String(await compile('# hi', {jsxImportSource: '@emotion/react', /* otherOptions… */}))
  ```
</details>

[Emotion][] is supported when
[`jsxImportSource` in `ProcessorOptions`][api-processor-options] is set to
`'@emotion/react'`.
You can optionally install and configure [`@mdx-js/react`][mdx-react] to
support context based component passing.

See also [¶ React][jsx-runtime-react],
which is used in Emotion,
and see [¶ Rollup][bundler-rollup] and [¶ webpack][bundler-webpack],
which you might be using,
for more info.

#### Ink

<details>
  <summary>Expand example</summary>

  ```mdx path="example.mdx"
  # Hi!
  ```

  ```js twoslash path="example.js"
  // @filename: types.d.ts
  import type {} from 'mdx'
  // @filename: example.js
  // @errors: 2769 -- something with Ink/twoslash/react getting different versions of React?
  // ---cut---
  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
      }
    })
  )
  ```

  Can be used with:

  ```sh
  node --loader=@mdx-js/node-loader example.js
  ```
</details>

[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][table-of-components] for what those are and Ink’s
docs on what they can be replaced with.

See also [¶ Node.js][js-engine-node] and [¶ React][jsx-runtime-react] for more
info.

#### Preact

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  import {compile} from '@mdx-js/mdx'

  const js = String(await compile('# hi', {jsxImportSource: 'preact', /* otherOptions… */}))
  ```
</details>

Preact is supported when [`jsxImportSource` in
`ProcessorOptions`][api-processor-options] is set to `'preact'`.
You can optionally install and configure [`@mdx-js/preact`][mdx-preact] to
support context based component passing.

See also [¶ Rollup][bundler-rollup], [¶ esbuild][bundler-esbuild], and
[¶ webpack][bundler-webpack],
which you might be using,
for more info.

#### React

React is supported by default.
You can optionally install and configure [`@mdx-js/react`][mdx-react] to
support context based component passing.

See also [¶ Rollup][bundler-rollup], [¶ esbuild][bundler-esbuild], and
[¶ webpack][bundler-webpack],
which you might be using,
for more info.

#### Theme UI

[Theme UI][theme-ui] has its own plugin to support MDX.
See [`@theme-ui/mdx`][theme-ui-mdx] on how to use MDX with Theme UI.

#### Svelte

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  import {compile} from '@mdx-js/mdx'

  const js = String(await compile('# hi', {jsxImportSource: 'svelte-jsx', /* otherOptions… */}))
  ```
</details>

Svelte is supported when [`jsxImportSource` in
`ProcessorOptions`][api-processor-options] is set to
[`'svelte-jsx'`][svelte-jsx].

See also [¶ Rollup][bundler-rollup], [¶ esbuild][bundler-esbuild], and
[¶ webpack][bundler-webpack],
which you might be using,
for more info.

#### Vue

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  import {compile} from '@mdx-js/mdx'

  const js = String(await compile('# hi', {jsxImportSource: 'vue', /* otherOptions… */}))
  ```
</details>

Vue is supported when [`jsxImportSource` in
`ProcessorOptions`][api-processor-options] is set to `'vue'`.
You can optionally install and configure [`@mdx-js/vue`][mdx-vue] to
support context based component passing.

See also [¶ Vite][build-system-vite],
which you might be using,
for more info.

#### Solid

<details>
  <summary>Expand example</summary>

  ```js twoslash path="example.js"
  import {compile} from '@mdx-js/mdx'

  const js = String(await compile('# hi', {jsxImportSource: 'solid-js/h', /* otherOptions… */}))
  ```
</details>

Solid is supported when [`jsxImportSource` in
`ProcessorOptions`][api-processor-options] is set to `'solid-js/h'`.

See also [¶ Rollup][bundler-rollup] and [¶ Vite][build-system-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`][mdx-node-loader].
See its readme on how to configure it.

#### Bun

MDX files can be imported in [Bun][] by using
[`@mdx-js/esbuild`][mdx-esbuild].

<details>
  <summary>Expand example</summary>

  ```toml path="bunfig.toml"
  preload = ["./bun-mdx.ts"]
  ```

  ```ts twoslash path="bun-mdx.ts"
  /// <reference types="bun-types" />
  // ---cut---
  import mdx from '@mdx-js/esbuild'
  import {type BunPlugin, plugin} from 'bun'

  await plugin(mdx() as unknown as BunPlugin)
  ```
</details>

## Further reading

* If you want to use MDX content in your project,
  see [§ Using MDX][use]
* If you’re getting errors integrating MDX,
  see [§ Troubleshooting MDX][trouble] or [§ Support][support]

[api-evaluate]: /packages/mdx/#evaluatefile-options

[api-processor-options]: /packages/mdx/#processoroptions

[astro]: https://astro.build/

[astro-framework-components]: https://docs.astro.build/en/core-concepts/framework-components/

[astro-mdx]: https://docs.astro.build/en/guides/integrations-guide/mdx/

[build-system-vite]: #vite

[bun]: https://bun.sh

[bundler-esbuild]: #esbuild

[bundler-rollup]: #rollup

[bundler-webpack]: #webpack

[definitely-typed-mdx]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mdx

[definitely-typed-react]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react

[docusaurus]: https://docusaurus.io

[docusaurus-markdown-react]: https://docusaurus.io/docs/next/markdown-features/react

[emotion]: https://emotion.sh/docs/introduction

[esbuild]: https://esbuild.github.io

[esbuild-target]: https://esbuild.github.io/api/#target

[eslint]: https://eslint.org

[eslint-mdx]: https://github.com/mdx-js/eslint-mdx

[gatsby]: https://www.gatsbyjs.com

[gatsby-plugin-mdx]: https://www.gatsbyjs.com/plugins/gatsby-plugin-mdx/

[github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

[ink]: https://github.com/vadimdemedes/ink

[javascript-engines-bun]: #bun

[js-engine-node]: #nodejs

[jsx]: #jsx

[jsx-runtime-emotion]: #emotion

[jsx-runtime-preact]: #preact

[jsx-runtime-react]: #react

[jsx-runtime-solid]: #solid

[jsx-runtime-svelte]: #svelte

[jsx-runtime-theme-ui]: #theme-ui

[jsx-runtime-vue]: #vue

[markdown-tm-language]: https://github.com/wooorm/markdown-tm-language

[mdx-analyzer]: https://github.com/mdx-js/mdx-analyzer

[mdx-esbuild]: /packages/esbuild/

[mdx-intellij-plugin]: https://github.com/JetBrains/intellij-plugins/tree/master/mdx

[mdx-loader]: /packages/loader/

[mdx-loader-babel]: /packages/loader/#combine-with-babel

[mdx-mdx]: /packages/mdx/

[mdx-node-loader]: /packages/node-loader/

[mdx-preact]: /packages/preact/

[mdx-react]: /packages/react/

[mdx-rollup]: /packages/rollup/

[mdx-rollup-babel]: /packages/rollup/#combine-with-babel

[mdx-sublime]: https://github.com/jonsuh/mdx-sublime

[mdx-vue]: /packages/vue/

[mdxjs-rs]: https://github.com/wooorm/mdxjs-rs

[mdxlint]: https://github.com/remcohaszing/mdxlint

[next]: https://nextjs.org

[next-configuring-mdx]: https://nextjs.org/docs/pages/building-your-application/configuring/mdx

[next-mdx]: https://github.com/vercel/next.js/tree/canary/packages/next-mdx

[node-js]: https://nodejs.org

[parcel]: https://parceljs.org

[parcel-mdx]: https://parceljs.org/languages/mdx/

[parcel-transformer-mdx]: https://github.com/EasyWebApp/Parcel-transformer-MDX

[remark plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md

[remark-lint]: https://github.com/remarkjs/remark-lint

[rollup]: https://rollupjs.org

[site-generator-next]: #nextjs

[support]: /community/support/

[svelte-jsx]: https://github.com/kenoxa/svelte-jsx

[table-of-components]: /table-of-components/

[theme-ui]: https://theme-ui.com

[theme-ui-mdx]: https://theme-ui.com/mdx

[trouble]: /docs/troubleshooting-mdx/

[typescript]: https://www.typescriptlang.org

[use]: /docs/using-mdx/

[vim-mdx-js]: https://github.com/jxnblk/vim-mdx-js

[vite]: https://vitejs.dev

[vite-build-target]: https://vitejs.dev/guide/build.html#browser-compatibility

[vm2]: https://github.com/patriksimek/vm2

[webpack]: https://webpack.js.org

[what]: /docs/what-is-mdx/


================================================
FILE: docs/docs/index.mdx
================================================
{
  /**
   * @import {Item} from '../_component/sort.js'
   */

  /**
   * @typedef Props
   * @property {Item} navigationTree
   */
}

import assert from 'node:assert/strict'
import {NavigationGroup} from '../_component/nav.jsx'

export const info = {
  author: [{name: 'MDX Contributors'}],
  modified: new Date('2024-07-04'),
  published: new Date('2021-11-01')
}
export const navSortSelf = 1

# Docs

These docs explain the core concepts of MDX.
How the format works, how to add it to your site, how to use MDX files, and how
to extend them.
Reading through these should give you a good understanding of MDX.

{
  (function () {
    const navigationTree = props.navigationTree
    const category = navigationTree.children.find(function (item) {
      return item.name === '/docs/'
    })
    assert(category)

    return (
      <nav>
        <NavigationGroup items={category.children} includeDescription />
      </nav>
    )
  })()
}


================================================
FILE: docs/docs/troubleshooting-mdx.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-10-18')
}
export const navSortSelf = 5

{/* lint disable maximum-heading-length */}

<Note type="info">
  **Note**: Had trouble with something that wasn’t explained here but should be?
  Please let us know.
  See [§ Contribute][contribute] for how to help.
</Note>

# Troubleshooting MDX

This article goes through several common problems and errors that might occur
when using MDX. {/* more */}
To understand how the MDX format works, we recommend that you start with
[§ What is MDX][what].
How to use [our packages][packages] is documented in their readmes.
To migrate to the latest MDX, see [§ Migrating from v1 to v2][migation-v2].

## Contents

* [Problems integrating MDX](#problems-integrating-mdx)
  * [ESM](#esm)
* [Problems using MDX](#problems-using-mdx)
  * [`` `options.renderer` is no longer supported ``](#optionsrenderer-is-no-longer-supported)
  * [`` Incorrect `format: 'detect'` ``](#incorrect-format-detect)
  * [`` Unexpected `format: 'detect'` ``](#unexpected-format-detect)
  * [`` Missing `pragma` in classic runtime with `pragmaImportSource` ``](#missing-pragma-in-classic-runtime-with-pragmaimportsource)
  * [`` Unexpected deprecated option `jsxRuntime: 'classic'`, `pragma`, `pragmaFrag`, or `pragmaImportSource` ``](#unexpected-deprecated-option-jsxruntime-classic-pragma-pragmafrag-or-pragmaimportsource)
  * [`` Expected `Fragment` given to `evaluate` ``](#expected-fragment-given-to-evaluate)
  * [`` Expected `jsx` given to `evaluate` ``](#expected-jsx-given-to-evaluate)
  * [`` Expected `jsxs` given to `evaluate` ``](#expected-jsxs-given-to-evaluate)
  * [``Unexpected missing `options.baseUrl` needed…``](#unexpected-missing-optionsbaseurl-needed)
* [Problems writing MDX](#problems-writing-mdx)
  * [`Could not parse import/exports with acorn: $error`](#could-not-parse-importexports-with-acorn-error)
  * [``Unexpected `$type` in code: only import/exports are supported``](#unexpected-type-in-code-only-importexports-are-supported)
  * [`` Unexpected end of file in expression, expected a corresponding closing brace for `{` ``](#unexpected-end-of-file-in-expression-expected-a-corresponding-closing-brace-for-)
  * [`Unexpected lazy line in expression in container`](#unexpected-lazy-line-in-expression-in-container)
  * [`Could not parse expression with acorn: $error`](#could-not-parse-expression-with-acorn-error)
  * [`Could not parse expression with acorn: Unexpected content after expression`](#could-not-parse-expression-with-acorn-unexpected-content-after-expression)
  * [`Unexpected extra content in spread: only a single spread is supported`](#unexpected-extra-content-in-spread-only-a-single-spread-is-supported)
  * [``Unexpected `$type` in code: only spread elements are supported``](#unexpected-type-in-code-only-spread-elements-are-supported)
  * [`Unexpected empty expression`](#unexpected-empty-expression)
  * [`Unexpected end of file $at, expected $expect`](#unexpected-end-of-file-at-expected-expect)
  * [`Unexpected character $at, expected $expect`](#unexpected-character-at-expected-expect)
  * [``Unexpected closing slash `/` in tag, expected an open tag first``](#unexpected-closing-slash--in-tag-expected-an-open-tag-first)
  * [`Unexpected lazy line in container, expected line to be…`](#unexpected-lazy-line-in-container-expected-line-to-be)
  * [`Unexpected attribute in closing tag, expected the end of the tag`](#unexpected-attribute-in-closing-tag-expected-the-end-of-the-tag)
  * [``Unexpected self-closing slash `/` in closing tag, expected the end of the tag``](#unexpected-self-closing-slash--in-closing-tag-expected-the-end-of-the-tag)
  * [``Unexpected closing tag `</$tag>`, expected corresponding closing tag for `<$tag>` ($at)``](#unexpected-closing-tag-tag-expected-corresponding-closing-tag-for-tag-at)
  * [``Cannot close `$type` ($at): a different token (`$type`, $at) is open``](#cannot-close-type-at-a-different-token-type-at-is-open)
  * [``Cannot close document, a token (`$type`, $at) is still open``](#cannot-close-document-a-token-type-at-is-still-open)

## Problems integrating MDX

### ESM

If you’re having problems integrating MDX with different tools, that’s likely
due to ESM: ECMAScript modules.
They’ve been in the works since 2015, we’ve supported them in MDX files from the
start, and in MDX version 2 we completely switched to them.
Many tools support ESM already.
Most other tools are working hard to support them.
Some still require extra configuration.

There’s a great [Gist by
**@sindresorhus**](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)
which explains in detail how to use ESM with many different tools.
If you’re having trouble with MDX, some other tool, and ESM,
you’ll likely find what you’re looking for there.
Please give it a thorough read.
If you’re still having problems, the issue tracker of the tools you’re
integrating MDX with might provide the answer.

If you’re having trouble with tools that don’t support ESM, such as Electron,
one short-term solution is to use a bundler to make a CJS version.

<details>
  <summary>Expand example of making a CJS bundle</summary>

  With [esbuild](https://esbuild.github.io), this bundles the ESM package
  `@mdx-js/mdx` as CJS in `vendor/mdx.js`:

  ```sh
  npx esbuild @mdx-js/mdx --bundle --platform=node --outfile=vendor/mdx.js
  ```
</details>

## Problems using MDX

Problems that occur when using MDX typically relate to the APIs of
[our packages][packages] and how to use them.
Please see the documentation of the packages, functions, and options you are
using for more info and examples.

### `` `options.renderer` is no longer supported ``

This error is thrown by [`@mdx-js/loader`][loader],
our webpack loader.
It was introduced in version 2 to help with migration.

The `renderer` option allowed arbitrary text to be injected before each compiled
MDX file.
This was typically used to support frameworks other than React such as Preact.
We now have options such as `jsxImportSource` for that and arbitrary JavaScript
can be added with `recmaPlugins`.
Because version 2 uses an AST based approach, it is no longer feasible to
support a `renderer`, so it was removed.

Please see [¶ Preact in § Getting started](/docs/getting-started/#preact) for
how to support Preact.
See [¶ Creating plugins in § Extending MDX](/docs/extending-mdx/#creating-plugins)
for how to create plugins.

### `` Incorrect `format: 'detect'` ``

### `` Unexpected `format: 'detect'` ``

The full error message in MDX 2 is as follows:

```mdx-invalid chrome=no
Incorrect `format: 'detect'`: `createProcessor` can support either `md` or `mdx`; it does not support detecting the format
```

The full error message in MDX 3 is:

```mdx-invalid chrome=no
Unexpected `format: 'detect'`, which is not supported by `createProcessor`, expected `'mdx'` or `'md'`
```

This error is thrown by [`@mdx-js/mdx`][mdx], our core compiler.
It was introduced in version 2 when the `format` option was introduced.

The `format` option, when configured with `'detect'`, allows inferring whether a
file is MDX or plain markdown.
Based on that information, plugins are configured differently, and with
different options.
This is impossible with `createProcessor` and `unified`.

To detect the format of passed files, please either use `compile` from
`@mdx-js/mdx` or one of the integrations.

### `` Missing `pragma` in classic runtime with `pragmaImportSource` ``

This error is thrown by [`@mdx-js/mdx`][mdx], our core compiler.
It was introduced in version 2 when the `jsxRuntime`, `pragma`, and
`pragmaImportSource` options were introduced.

This error is thrown when `jsxRuntime` is configured with `'classic'` (the
default is `'automatic'`), `pragmaImportSource` is defined (the default is
`'react'`), but `pragma` is defined as a falsey value (the default is
`React.createElement`).

If you are using the classic runtime, you have to define a `pragma`.

### `` Unexpected deprecated option `jsxRuntime: 'classic'`, `pragma`, `pragmaFrag`, or `pragmaImportSource` ``

This is a warning.
It is not an error.
You can keep on using these options, but expect them to be removed in the
future.

All major frameworks currently support the automatic JSX runtime.
The classic runtime, from MDX perspective, comes with several potential
problems.

Because of that, we strongly recommend using an automatic JSX runtime and are
considering removing support for the classic JSX runtime.

### `` Expected `Fragment` given to `evaluate` ``

### `` Expected `jsx` given to `evaluate` ``

### `` Expected `jsxs` given to `evaluate` ``

These errors are thrown by [`@mdx-js/mdx`][loader],
our core compiler.
They were introduced in version 2 when `evaluate` (and `evaluateSync`) were
introduced.

`evaluate` supports React and other frameworks.
But these frameworks must support an automatic JSX runtime that exposes these
three exports.
If you’re getting this error, that means that either a) the framework does not
support the automatic JSX runtime, or b) that you’re not passing them correctly
to `evaluate`.

Please see [`evaluate` in `@mdx-js/mdx`](/packages/mdx/#evaluatefile-options)
for examples on how to pass these values.

### ``Unexpected missing `options.baseUrl` needed…``

The full error message in MDX is as follows:

```mdx-invalid chrome=no
Unexpected missing `options.baseUrl` needed to support `export … from`, `import`, or `import.meta.url` when generating `function-body`
```

This error is thrown when MDX runs that is specifically compiled with
`evaluate`, or with the `outputFormat: 'function-body'` option to evluate
somewhere later, and `import.meta.url`, `import`, or `export … from` is used.
These JavaScript features depend on a particular URL to run from, which is not
available or not correct when running a function body.
To solve this, pass a `baseUrl` option.
Likely set to `import.meta.url` (or `window.location.href`).

## Problems writing MDX

Problems that occur when writing MDX typically have relate to how to combine
JS(X) and markdown.
It’s an odd mix of two languages: markdown is **whitespace sensitive** and
**forgiving** (what you type may not exactly work but it won’t crash) whereas
JavaScript is **whitespace insensitive** and **unforgiving** (it does crash on
typos).

Errors typically fall in these three categories:

* **Not escaping `<` and `{`**
  — Escape these (`\<`, `\{`) if you mean them as plain text instead of JS(X)
* **Incorrect interleaving**
  — See the rules in
  [¶ Interleaving in § What is MDX?][interleaving]
* **Broken JavaScript**
  — Make sure the JavaScript you write is valid

### `Could not parse import/exports with acorn: $error`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when the keywords `import` or `export` are found at the start of a
line but they are not followed by valid JavaScript.
An example is:

```mdx-invalid chrome=no
import 1/1
```

The reason for this error is that the parser is expecting a JavaScript import or
export statement.
If you want the word import or export, make sure it’s not at the start of a
paragraph.
If you do want an import or export statement, please make sure that it’s valid
JavaScript.

### ``Unexpected `$type` in code: only import/exports are supported``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when, after an `import` or `export` statement, more JavaScript is
found.
An example is:

```mdx-invalid chrome=no
export const a = 1
const b = 2
```

The reason for this error is that we only allow `import` and `export` to define
data.
If you want to define a variable or function, please export it.

### `` Unexpected end of file in expression, expected a corresponding closing brace for `{` ``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there is an opening curly brace not followed by a closing brace.
An example is:

```mdx-invalid chrome=no
a { b
```

The reason for this error is that the parser is expecting another curly brace.
If you just want a brace but not an expression, escape it: `\{`.
If you do want an expression, please make sure to close it with a closing brace
`}`.
If there is a closing brace somewhere, make sure that the braces are each on
their own lines with no text before the opening brace and no text after the
closing brace, or that there are no blank lines between the braces.

### `Unexpected lazy line in expression in container`

This error is thrown by our MDX parser.
It was introduced in version 3.
It occurs when containers with lazy lines are combined with expressions
An example is:

```mdx-invalid chrome=no
* {1 +
2}

> {1 +
2}
```

The reason for this error is that the parser it likely points to a bug.
Be explicit with your list items and block quotes:

```mdx-invalid chrome=no
* {1 +
  2}

> {1 +
> 2}
```

### `Could not parse expression with acorn: $error`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are matching curly braces that, when interpreting what’s
inside them as JavaScript, results in a syntax error.
An example is:

```mdx-invalid chrome=no
a {const b = 'c'} d
```

Another example:

```mdx-invalid chrome=no
a {!} d
```

The reason for this error is that the parser is expecting a JavaScript
expression.
If you just want braces instead of an expression, escape the opening: `\{`.
If you do want an expression, make sure that it’s valid JavaScript and that it
is an expression.
That means statements (such as `if` and `else` and `for` loops) do not work.
If you need complex logic, you can wrap statements and whole programs into an
IIFE, or move it out to a different file, export it from there, and import it in
MDX.

### `Could not parse expression with acorn: Unexpected content after expression`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are matching curly braces that, and valid JavaScript is
inside them, but there’s too much JavaScript.
An example is:

```mdx-invalid chrome=no
a {'b' 'c'} d
```

The reason for this error is that the parser is expecting a single JavaScript
expression yielding one value.
If you just want braces instead of an expression, escape the opening: `\{`.
If you do want an expression, make sure that it yields a single value.

### `Unexpected extra content in spread: only a single spread is supported`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when there are multiple values spread into a JSX tag.
An example is:

```mdx-invalid chrome=no
<div {...a, ...b} />
```

The reason for this error is that JSX only allows spreading a single value at a
time:

```mdx chrome=no
<div {...a} {...b} />
```

### ``Unexpected `$type` in code: only spread elements are supported``

### `Unexpected empty expression`

These errors are thrown by our MDX parser.
They were introduced in version 2.
They occur when something other than a spread is used in braces.
An example is:

```mdx-invalid chrome=no
<div {values} {/* comment */} {} />
```

The reason for this error is that JSX only allows spreading values:

```mdx chrome=no
<div {...a} />
```

### `Unexpected end of file $at, expected $expect`

### `Unexpected character $at, expected $expect`

These errors are thrown by our MDX parser.
They were introduced in MDX version 2.
They occur when something unexpected was found in a JSX tag.
Some examples are:

```mdx-invalid chrome=no
<
<.>
</
</.>
<a
<a?>
<a:
<a:+>
<a.
<a./>
<a b
<a b!>
<a b:
<a b:1>
<a b=
<a b=>
<a b="
<a b='
<a b={
<a/
<a/->
```

The reason for these errors is that JSX has a very strict grammar and expects
tags to be valid.
There are different solutions depending on what was expected.
Please read the error message carefully as it indicates where the problem
occurred and what was expected instead.

### ``Unexpected closing slash `/` in tag, expected an open tag first``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is found but there are no open tags.
An example is:

```mdx-invalid chrome=no
</div>
```

The reason for this error is that only open tags can be closed.
You probably forgot an opening tag somewhere.

### `Unexpected lazy line in container, expected line to be…`

This error is thrown by our MDX parser.
It was introduced in version 3.
It occurs when containers with lazy lines are combined with JSX.
An example is:

```mdx-invalid chrome=no
* <x
y />

> <x
y />
```

The reason for this error is that the parser it likely points to a bug.
Be explicit with your list items and block quotes:

```mdx-invalid chrome=no
* <x
  y />

> <x
> y />
```

### `Unexpected attribute in closing tag, expected the end of the tag`

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when attributes are placed on closing tags.
An example is:

```mdx-invalid chrome=no
<h1>Text</h1 id="text">
```

The reason for this error is that only open tags can have attributes.
Move these attributes to the corresponding opening tag.

### ``Unexpected self-closing slash `/` in closing tag, expected the end of the tag``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is also marked as self-closing.
An example is:

```mdx-invalid chrome=no
<h1>Text</h1/>
```

The reason for this error is that only opening tags can be marked as
self-closing.
Remove the slash after the tag name and before `>`.

### ``Unexpected closing tag `</$tag>`, expected corresponding closing tag for `<$tag>` ($at)``

This error is thrown by our MDX parser.
It was introduced in version 2.
It occurs when a closing tag is seen that does not match the expected opening
tag.
An example is:

```mdx-invalid chrome=no
<a>Text</b>
```

The reason for this error is that tags must match in JSX.
You likely forgot to open or close one of the two correctly.

### ``Cannot close `$type` ($at): a different token (`$type`, $at) is open``

### ``Cannot close document, a token (`$type`, $at) is still open``

This error is thrown by our MDX parser.
It was introduced in version 2.
It typically occurs when markdown and JSX are not interleaved correctly.
An example is:

```mdx-invalid chrome=no
> <div>
```

The reason for this error is that a markdown construct ends while there are
still tags open.
See the rules on
[¶ Interleaving in § What is MDX?][interleaving]

[contribute]: /community/contribute/

[interleaving]: /docs/what-is-mdx/#interleaving

[loader]: /packages/loader/

[mdx]: /packages/mdx/

[migation-v2]: /migrating/v2/

[packages]: /packages/

[what]: /docs/what-is-mdx/


================================================
FILE: docs/docs/using-mdx.mdx
================================================
import {Note} from '../_component/note.jsx'

export const info = {
  author: [
    {github: 'wooorm', name: 'Titus Wormer'}
  ],
  modified: new Date('2025-01-27'),
  published: new Date('2021-09-30')
}
export const navSortSelf = 3

# Using MDX

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. {/* more */}
See [§ Getting started][start] for how to integrate MDX into your project.
To understand how the MDX format works, we recommend that you start with
[§ What is MDX][what].

## Contents

* [How MDX works](#how-mdx-works)
* [MDX content](#mdx-content)
  * [Props](#props)
  * [Components](#components)
  * [Layout](#layout)
* [MDX provider](#mdx-provider)

## How MDX works

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

```mdx path="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:

```jsx twoslash path="output-outline.jsx"
/* @jsxRuntime automatic */
/* @jsxImportSource react */

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

export default function MDXContent() {
  return <h1>Hello <Thing /></h1>
}
```

Some observations:

* The output is serialized JavaScript that still needs to be evaluated
* A comment is injected to configure how JSX is handled
* It’s a complete file with import/exports
* A component (`MDXContent`) is exported

The *actual* output is:

```js twoslash path="output-actual.js"
// @noErrors
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 || {}
Download .txt
gitextract_mjw34tia/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── bb.yml
│       ├── main.yml
│       └── website.yml
├── .gitignore
├── .prettierignore
├── .vercelignore
├── changelog.md
├── docs/
│   ├── .remarkrc.js
│   ├── 404.mdx
│   ├── _asset/
│   │   ├── editor.jsx
│   │   ├── index.css
│   │   └── index.js
│   ├── _component/
│   │   ├── blog.jsx
│   │   ├── foot-site.jsx
│   │   ├── home.jsx
│   │   ├── icon/
│   │   │   ├── github.jsx
│   │   │   ├── mdx.jsx
│   │   │   └── open-collective.jsx
│   │   ├── layout.jsx
│   │   ├── nav-site.jsx
│   │   ├── nav.jsx
│   │   ├── note.jsx
│   │   ├── snowfall.jsx
│   │   └── sort.js
│   ├── _config.js
│   ├── blog/
│   │   ├── conf.mdx
│   │   ├── custom-pragma.mdx
│   │   ├── index.mdx
│   │   ├── shortcodes.mdx
│   │   ├── v1.mdx
│   │   ├── v2.mdx
│   │   └── v3.mdx
│   ├── community/
│   │   ├── about.mdx
│   │   ├── contribute.mdx
│   │   ├── index.mdx
│   │   ├── projects.mdx
│   │   ├── sponsor.mdx
│   │   └── support.mdx
│   ├── docs/
│   │   ├── extending-mdx.mdx
│   │   ├── getting-started.mdx
│   │   ├── index.mdx
│   │   ├── troubleshooting-mdx.mdx
│   │   ├── using-mdx.mdx
│   │   └── what-is-mdx.mdx
│   ├── guides/
│   │   ├── embed.mdx
│   │   ├── frontmatter.mdx
│   │   ├── gfm.mdx
│   │   ├── index.mdx
│   │   ├── injecting-components.mdx
│   │   ├── math.mdx
│   │   ├── mdx-on-demand.mdx
│   │   └── syntax-highlighting.mdx
│   ├── index.mdx
│   ├── migrating/
│   │   ├── v1.mdx
│   │   ├── v2.mdx
│   │   └── v3.mdx
│   ├── packages/
│   │   └── index.mdx
│   ├── playground.mdx
│   └── table-of-components.mdx
├── license
├── package.json
├── packages/
│   ├── esbuild/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── loader/
│   │   ├── index.cjs
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── mdx/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   ├── compile.js
│   │   │   ├── core.js
│   │   │   ├── evaluate.js
│   │   │   ├── node-types.js
│   │   │   ├── plugin/
│   │   │   │   ├── recma-build-jsx-transform.js
│   │   │   │   ├── recma-document.js
│   │   │   │   ├── recma-jsx-rewrite.js
│   │   │   │   ├── rehype-remove-raw.js
│   │   │   │   └── remark-mark-and-unravel.js
│   │   │   ├── run.js
│   │   │   ├── types.d.ts
│   │   │   └── util/
│   │   │       ├── create-format-aware-processors.js
│   │   │       ├── estree-util-create.js
│   │   │       ├── estree-util-declaration-to-expression.js
│   │   │       ├── estree-util-is-declaration.js
│   │   │       ├── estree-util-specifiers-to-declarations.js
│   │   │       ├── estree-util-to-binary-addition.js
│   │   │       ├── estree-util-to-id-or-member-expression.js
│   │   │       ├── extnames-to-regex.js
│   │   │       ├── extnames.js
│   │   │       ├── resolve-evaluate-options.js
│   │   │       └── resolve-file-and-options.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   ├── compile.js
│   │   │   ├── context/
│   │   │   │   ├── components.js
│   │   │   │   ├── data.js
│   │   │   │   └── run.js
│   │   │   ├── core.js
│   │   │   ├── evaluate.js
│   │   │   ├── index.js
│   │   │   └── syntax.js
│   │   └── tsconfig.json
│   ├── node-loader/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   ├── condition.default.js
│   │   │   ├── condition.development.js
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── preact/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.jsx
│   │   └── tsconfig.json
│   ├── react/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.jsx
│   │   └── tsconfig.json
│   ├── remark-mdx/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   └── index.js
│   │   └── tsconfig.json
│   ├── rollup/
│   │   ├── index.js
│   │   ├── lib/
│   │   │   └── index.js
│   │   ├── license
│   │   ├── package.json
│   │   ├── readme.md
│   │   ├── test/
│   │   │   ├── index.js
│   │   │   └── vite-entry.mdx
│   │   └── tsconfig.json
│   └── vue/
│       ├── index.js
│       ├── lib/
│       │   └── index.js
│       ├── license
│       ├── package.json
│       ├── readme.md
│       ├── test/
│       │   └── index.js
│       └── tsconfig.json
├── readme.md
├── renovate.json5
├── script/
│   └── jsx-loader.js
├── tsconfig.json
├── vercel.json
└── website/
    ├── generate.js
    ├── mdx-loader.js
    ├── post.js
    ├── prep.js
    ├── schema-description.js
    └── types.d.ts
Download .txt
SYMBOL INDEX (152 symbols across 59 files)

FILE: docs/.remarkrc.js
  function check (line 35) | function check(value) {

FILE: docs/_asset/editor.jsx
  function init (line 110) | function init(main) {
  function Playground (line 131) | function Playground() {
  function ErrorFallback (line 581) | function ErrorFallback(properties) {
  function DisplayError (line 601) | function DisplayError(properties) {
  function cleanUnistTree (line 621) | function cleanUnistTree(node) {
  function cleanUnistNode (line 632) | function cleanUnistNode(node) {
  function removeFromEstree (line 664) | function removeFromEstree(node) {

FILE: docs/_asset/index.js
  function oncopyonclick (line 102) | function oncopyonclick() {
  function popoverShow (line 127) | function popoverShow(popoverTarget) {

FILE: docs/_component/blog.jsx
  function BlogEntry (line 36) | function BlogEntry(properties) {
  function BlogGroup (line 112) | function BlogGroup(properties) {

FILE: docs/_component/foot-site.jsx
  function FootSite (line 4) | function FootSite() {

FILE: docs/_component/home.jsx
  function Home (line 32) | function Home(properties) {

FILE: docs/_component/icon/github.jsx
  function GitHub (line 3) | function GitHub() {

FILE: docs/_component/icon/mdx.jsx
  function Mdx (line 3) | function Mdx() {

FILE: docs/_component/icon/open-collective.jsx
  function OpenCollective (line 3) | function OpenCollective() {

FILE: docs/_component/layout.jsx
  function Layout (line 35) | function Layout(properties) {
  function entryToTitle (line 244) | function entryToTitle(d) {
  function accumulateReadingTime (line 254) | function accumulateReadingTime(d) {

FILE: docs/_component/nav-site.jsx
  function NavigationSiteSkip (line 22) | function NavigationSiteSkip() {
  function NavigationSite (line 40) | function NavigationSite(properties) {

FILE: docs/_component/nav.jsx
  function NavigationGroup (line 52) | function NavigationGroup(properties) {
  function NavigationItem (line 75) | function NavigationItem(properties) {

FILE: docs/_component/note.jsx
  function Note (line 28) | function Note(properties) {

FILE: docs/_component/snowfall.jsx
  function Chart (line 24) | function Chart(properties) {

FILE: docs/_component/sort.js
  function sortItems (line 28) | function sortItems(items, sortString = 'navSortSelf,meta.title') {

FILE: packages/esbuild/lib/index.js
  function esbuild (line 70) | function esbuild(options) {
  function vfileMessageToEsbuild (line 162) | function vfileMessageToEsbuild(state, message) {

FILE: packages/esbuild/test/index.js
  function warn (line 382) | function warn() {
  function crash (line 479) | function crash() {
  function inlinePlugin (line 611) | function inlinePlugin(contents) {

FILE: packages/loader/index.cjs
  function loader (line 28) | function loader(code) {

FILE: packages/loader/lib/index.js
  function loader (line 51) | function loader(value, callback) {
  function getOptionsHash (line 119) | function getOptionsHash(options) {

FILE: packages/mdx/lib/compile.js
  function compile (line 37) | function compile(vfileCompatible, compileOptions) {
  function compileSync (line 54) | function compileSync(vfileCompatible, compileOptions) {

FILE: packages/mdx/lib/core.js
  function createProcessor (line 161) | function createProcessor(options) {

FILE: packages/mdx/lib/evaluate.js
  function evaluate (line 47) | async function evaluate(file, options) {
  function evaluateSync (line 66) | function evaluateSync(file, options) {

FILE: packages/mdx/lib/plugin/recma-build-jsx-transform.js
  function recmaBuildJsxTransform (line 24) | function recmaBuildJsxTransform(options) {

FILE: packages/mdx/lib/plugin/recma-document.js
  function recmaDocument (line 51) | function recmaDocument(options) {
  function injectPragma (line 736) | function injectPragma(tree, name, value) {
  function resolveDynamicMdxSpecifier (line 748) | function resolveDynamicMdxSpecifier(importMetaUrl) {
  function createImportMetaUrlVariable (line 876) | function createImportMetaUrlVariable() {

FILE: packages/mdx/lib/plugin/recma-jsx-rewrite.js
  function recmaJsxRewrite (line 62) | function recmaJsxRewrite(options) {
  function createImportProvider (line 561) | function createImportProvider(providerImportSource, outputFormat) {
  function isNamedFunction (line 596) | function isNamedFunction(node, name) {
  function inScope (line 608) | function inScope(scopes, id) {

FILE: packages/mdx/lib/plugin/rehype-remove-raw.js
  function rehypeRemoveRaw (line 16) | function rehypeRemoveRaw() {

FILE: packages/mdx/lib/plugin/remark-mark-and-unravel.js
  function remarkMarkAndUnravel (line 19) | function remarkMarkAndUnravel() {

FILE: packages/mdx/lib/run.js
  function run (line 23) | async function run(code, options) {
  function runSync (line 41) | function runSync(code, options) {

FILE: packages/mdx/lib/types.d.ts
  type EsastData (line 4) | interface EsastData extends UnistData {
  type EsastCommentData (line 14) | interface EsastCommentData extends EsastData {
  type BaseNode (line 26) | interface BaseNode {
  type Comment (line 35) | interface Comment {
  type MdxJsxFlowElementData (line 47) | interface MdxJsxFlowElementData {
  type MdxJsxTextElementData (line 57) | interface MdxJsxTextElementData {
  type CompileResultMap (line 69) | interface CompileResultMap {

FILE: packages/mdx/lib/util/create-format-aware-processors.js
  function createFormatAwareProcessors (line 37) | function createFormatAwareProcessors(compileOptions) {

FILE: packages/mdx/lib/util/estree-util-create.js
  function create (line 16) | function create(from, to) {

FILE: packages/mdx/lib/util/estree-util-declaration-to-expression.js
  function declarationToExpression (line 24) | function declarationToExpression(declaration) {

FILE: packages/mdx/lib/util/estree-util-is-declaration.js
  function isDeclaration (line 21) | function isDeclaration(node) {

FILE: packages/mdx/lib/util/estree-util-specifiers-to-declarations.js
  function specifiersToDeclarations (line 26) | function specifiersToDeclarations(specifiers, init) {

FILE: packages/mdx/lib/util/estree-util-to-binary-addition.js
  function toBinaryAddition (line 13) | function toBinaryAddition(expressions) {

FILE: packages/mdx/lib/util/estree-util-to-id-or-member-expression.js
  function toIdOrMemberExpression (line 20) | function toIdOrMemberExpression(ids) {
  function toJsxIdOrMemberExpression (line 54) | function toJsxIdOrMemberExpression(ids) {

FILE: packages/mdx/lib/util/extnames-to-regex.js
  function extnamesToRegex (line 9) | function extnamesToRegex(extnames) {

FILE: packages/mdx/lib/util/resolve-evaluate-options.js
  function resolveEvaluateOptions (line 58) | function resolveEvaluateOptions(options) {

FILE: packages/mdx/lib/util/resolve-file-and-options.js
  function resolveFileAndOptions (line 21) | function resolveFileAndOptions(vfileCompatible, options) {
  function looksLikeAVFile (line 46) | function looksLikeAVFile(value) {

FILE: packages/mdx/test/compile.js
  function capture (line 61) | function capture(...parameters) {
  function plugin (line 119) | function plugin() {
  function plugin (line 144) | function plugin() {
  function plugin (line 171) | function plugin() {
  function plugin (line 199) | function plugin() {
  function plugin (line 225) | function plugin() {
  method X (line 324) | X(properties) {
  method y (line 348) | y(properties) {
  function X (line 381) | function X(properties) {
  function Y (line 391) | function Y(properties) {
  method em (line 405) | em(properties) {
  method em (line 429) | em(properties) {
  method Y (line 465) | Y() {
  method Y (line 493) | Y() {
  method z (line 542) | z() {
  method wrapper (line 576) | wrapper(properties) {
  method wrapper (line 623) | wrapper(properties) {
  method em (line 800) | em(properties) {
  function plugin (line 942) | function plugin() {
  function plugin (line 995) | function plugin() {
  function plugin (line 1478) | function plugin() {
  function plugin (line 1515) | function plugin() {

FILE: packages/mdx/test/context/components.js
  function Pill (line 13) | function Pill(properties) {
  function Layout (line 23) | function Layout(properties) {

FILE: packages/mdx/test/context/run.js
  function run (line 14) | async function run(input) {
  function runWhole (line 26) | async function runWhole(input) {

FILE: packages/mdx/test/evaluate.js
  method X (line 396) | X() {
  method X (line 417) | X() {

FILE: packages/mdx/test/syntax.js
  function plugin (line 418) | function plugin() {

FILE: packages/node-loader/lib/index.js
  function createLoader (line 39) | function createLoader(loaderOptions) {
  function configure (line 98) | function configure(options) {

FILE: packages/preact/lib/index.js
  function useMDXComponents (line 40) | function useMDXComponents(components) {
  function MDXProvider (line 60) | function MDXProvider(properties) {

FILE: packages/preact/test/index.jsx
  method h1 (line 35) | h1(properties) {
  method wrapper (line 64) | wrapper(properties) {
  method h1 (line 88) | h1(properties) {
  method h2 (line 91) | h2(properties) {
  method h2 (line 98) | h2(properties) {
  method h1 (line 122) | h1(properties) {
  method h2 (line 125) | h2(properties) {
  method h2 (line 133) | h2(properties) {
  method h1 (line 159) | h1(properties) {
  method h1 (line 186) | h1(properties) {
  method h2 (line 195) | h2(properties) {

FILE: packages/react/lib/index.js
  function useMDXComponents (line 39) | function useMDXComponents(components) {
  function MDXProvider (line 65) | function MDXProvider(properties) {

FILE: packages/react/test/index.jsx
  method h1 (line 33) | h1(properties) {
  method wrapper (line 59) | wrapper(properties) {
  method h1 (line 83) | h1(properties) {
  method h2 (line 86) | h2(properties) {
  method h2 (line 93) | h2(properties) {
  method h1 (line 117) | h1(properties) {
  method h2 (line 120) | h2(properties) {
  method h2 (line 128) | h2(properties) {
  method h1 (line 154) | h1(properties) {
  method h1 (line 181) | h1(properties) {
  method h2 (line 190) | h2(properties) {

FILE: packages/remark-mdx/lib/index.js
  function remarkMdx (line 29) | function remarkMdx(options) {

FILE: packages/remark-mdx/test/index.js
  function clean (line 466) | function clean(tree) {
  function onvisit (line 477) | function onvisit(node) {

FILE: packages/rollup/lib/index.js
  function rollup (line 68) | function rollup(options) {

FILE: packages/vue/lib/index.js
  method default (line 25) | default() {
  method setup (line 31) | setup(properties) {
  method render (line 40) | render() {
  function useMDXComponents (line 55) | function useMDXComponents() {

FILE: packages/vue/test/index.js
  method data (line 77) | data() {
  function evaluate (line 122) | async function evaluate(value) {
  function vueToString (line 141) | async function vueToString(root, rootProperties) {

FILE: script/jsx-loader.js
  function createLoader (line 12) | function createLoader() {

FILE: website/generate.js
  function rehypeLazyCss (line 273) | function rehypeLazyCss(styles) {

FILE: website/mdx-loader.js
  method onUnRecoverableConfigFileDiagnostic (line 65) | onUnRecoverableConfigFileDiagnostic(x) {
  function link (line 125) | function link() {
  function unifiedInferRemoteMeta (line 146) | function unifiedInferRemoteMeta() {
  function recmaInjectMeta (line 191) | function recmaInjectMeta(options) {
  function rehypePrettyCodeBlocks (line 261) | function rehypePrettyCodeBlocks() {

FILE: website/prep.js
  function buildRedirect (line 76) | function buildRedirect(to) {

FILE: website/types.d.ts
  type BaseNode (line 5) | interface BaseNode {
  type ElementData (line 24) | interface ElementData {
  type DataMapMeta (line 36) | interface DataMapMeta {
  type DataMap (line 52) | interface DataMap {
Condensed preview — 167 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (745K chars).
[
  {
    "path": ".editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": ".github/workflows/bb.yml",
    "chars": 336,
    "preview": "jobs:\n  main:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: unifiedjs/beep-boop-beta@main\n        with:\n          "
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 986,
    "preview": "jobs:\n  small:\n    env:\n      PUPPETEER_SKIP_DOWNLOAD: 1\n    name: test / ${{matrix.os}} / ${{matrix.node}}\n    runs-on:"
  },
  {
    "path": ".github/workflows/website.yml",
    "chars": 703,
    "preview": "jobs:\n  deploy:\n    environment:\n      name: Website\n      url: ${{steps.deployment.outputs.page_url}}\n    permissions:\n"
  },
  {
    "path": ".gitignore",
    "chars": 129,
    "preview": ".DS_Store\ncoverage/\nnode_modules/\n*.d.cts\n*.d.ts\n*.map\n*.tsbuildinfo\n/public/\n!/packages/mdx/lib/types.d.ts\n!/website/ty"
  },
  {
    "path": ".prettierignore",
    "chars": 43,
    "preview": "node_modules/\ncoverage/\npublic/\n*.md\n*.mdx\n"
  },
  {
    "path": ".vercelignore",
    "chars": 14,
    "preview": "node_modules/\n"
  },
  {
    "path": "changelog.md",
    "chars": 116,
    "preview": "# Changelog\n\nSee [GitHub Releases][releases] for the changelog.\n\n[releases]: https://github.com/mdx-js/mdx/releases\n"
  },
  {
    "path": "docs/.remarkrc.js",
    "chars": 1043,
    "preview": "/**\n * @import {CheckFlag} from 'remark-lint-fenced-code-flag'\n * @import {Preset} from 'unified'\n */\n\nimport remarkPres"
  },
  {
    "path": "docs/404.mdx",
    "chars": 541,
    "preview": "import {Note} from './_component/note.jsx'\n\nexport {Home as default} from './_component/home.jsx'\nexport const navExclud"
  },
  {
    "path": "docs/_asset/editor.jsx",
    "chars": 18496,
    "preview": "/* @jsxRuntime automatic */\n/* @jsxImportSource react */\n\n/* eslint-disable unicorn/prefer-global-this */\n\n/**\n * @impor"
  },
  {
    "path": "docs/_asset/index.css",
    "chars": 26218,
    "preview": ":root {\n  --sans:\n    system-ui, -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial,\n    sans-serif, 'Apple"
  },
  {
    "path": "docs/_asset/index.js",
    "chars": 4234,
    "preview": "/* eslint-disable unicorn/prefer-query-selector */\n/// <reference lib=\"dom\" />\n\nimport docsearch_ from '@docsearch/js'\ni"
  },
  {
    "path": "docs/_component/blog.jsx",
    "chars": 3230,
    "preview": "/**\n * @import {ReactNode} from 'react'\n * @import {Item} from './sort.js'\n */\n\n/**\n * @typedef EntryProperties\n *   Pro"
  },
  {
    "path": "docs/_component/foot-site.jsx",
    "chars": 1215,
    "preview": "import React from 'react'\nimport {config} from '../_config.js'\n\nexport function FootSite() {\n  return (\n    <footer clas"
  },
  {
    "path": "docs/_component/home.jsx",
    "chars": 1194,
    "preview": "/**\n * @import {ReactNode} from 'react'\n * @import {Data} from 'vfile'\n * @import {Item} from './sort.js'\n */\n\n/**\n * @t"
  },
  {
    "path": "docs/_component/icon/github.jsx",
    "chars": 1147,
    "preview": "import React from 'react'\n\nexport function GitHub() {\n  return (\n    <svg\n      role=\"img\"\n      aria-label=\"GitHub\"\n   "
  },
  {
    "path": "docs/_component/icon/mdx.jsx",
    "chars": 720,
    "preview": "import React from 'react'\n\nexport function Mdx() {\n  return (\n    <svg\n      role=\"img\"\n      aria-label=\"MDX\"\n      cla"
  },
  {
    "path": "docs/_component/icon/open-collective.jsx",
    "chars": 886,
    "preview": "import React from 'react'\n\nexport function OpenCollective() {\n  return (\n    <svg\n      role=\"img\"\n      aria-label=\"Ope"
  },
  {
    "path": "docs/_component/layout.jsx",
    "chars": 6924,
    "preview": "/**\n * @import {ReactNode} from 'react'\n * @import {Data} from 'vfile'\n * @import {Item} from './sort.js'\n */\n\n/**\n * @t"
  },
  {
    "path": "docs/_component/nav-site.jsx",
    "chars": 1871,
    "preview": "/**\n * @import {ReactNode} from 'react'\n * @import {Item} from './sort.js'\n */\n\n/**\n * @typedef Properties\n *   Properti"
  },
  {
    "path": "docs/_component/nav.jsx",
    "chars": 3896,
    "preview": "// Augment vfile data:\n/// <reference types=\"rehype-infer-description-meta\" />\n\n/**\n * @import {ElementContent} from 'ha"
  },
  {
    "path": "docs/_component/note.jsx",
    "chars": 774,
    "preview": "/**\n * @import {ReactNode} from 'react'\n */\n\n/**\n * @typedef {'important' | 'info' | 'legacy'} NoteType\n *   Type.\n *\n *"
  },
  {
    "path": "docs/_component/snowfall.jsx",
    "chars": 764,
    "preview": "/**\n * @import {ReactNode} from 'react'\n */\n\n/**\n * @typedef Properties\n *   Properties.\n * @property {string} color\n * "
  },
  {
    "path": "docs/_component/sort.js",
    "chars": 1844,
    "preview": "/**\n * @import {Data} from 'vfile'\n */\n\n/**\n * @typedef Item\n *   Item.\n * @property {string} name\n *   Name.\n * @proper"
  },
  {
    "path": "docs/_config.js",
    "chars": 3365,
    "preview": "const site = new URL('https://mdxjs.com')\nconst git = new URL('../', import.meta.url)\nconst gh = new URL('https://github"
  },
  {
    "path": "docs/blog/conf.mdx",
    "chars": 2764,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/blog/custom-pragma.mdx",
    "chars": 6405,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'christopherbiscardi', name:"
  },
  {
    "path": "docs/blog/index.mdx",
    "chars": 861,
    "preview": "{\n  /**\n   * @import {Item} from '../_component/sort.js'\n   */\n\n  /**\n   * @typedef Props\n   * @property {Item} navigati"
  },
  {
    "path": "docs/blog/shortcodes.mdx",
    "chars": 1688,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/blog/v1.mdx",
    "chars": 9031,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/blog/v2.mdx",
    "chars": 12845,
    "preview": "import {Note} from '../_component/note.jsx'\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer"
  },
  {
    "path": "docs/blog/v3.mdx",
    "chars": 4012,
    "preview": "import {Note} from '../_component/note.jsx'\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer"
  },
  {
    "path": "docs/community/about.mdx",
    "chars": 5580,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/community/contribute.mdx",
    "chars": 4184,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/community/index.mdx",
    "chars": 853,
    "preview": "{\n  /**\n   * @import {Item} from '../_component/sort.js'\n   */\n\n  /**\n   * @typedef Props\n   * @property {Item} navigati"
  },
  {
    "path": "docs/community/projects.mdx",
    "chars": 1754,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/community/sponsor.mdx",
    "chars": 5507,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2025-01-27'),\n"
  },
  {
    "path": "docs/community/support.mdx",
    "chars": 1856,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/docs/extending-mdx.mdx",
    "chars": 7708,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/docs/getting-started.mdx",
    "chars": 26622,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/docs/index.mdx",
    "chars": 940,
    "preview": "{\n  /**\n   * @import {Item} from '../_component/sort.js'\n   */\n\n  /**\n   * @typedef Props\n   * @property {Item} navigati"
  },
  {
    "path": "docs/docs/troubleshooting-mdx.mdx",
    "chars": 18821,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/docs/using-mdx.mdx",
    "chars": 16589,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/docs/what-is-mdx.mdx",
    "chars": 9460,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/guides/embed.mdx",
    "chars": 3640,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2025-01-27'),\n"
  },
  {
    "path": "docs/guides/frontmatter.mdx",
    "chars": 2935,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2025-01-27'),\n"
  },
  {
    "path": "docs/guides/gfm.mdx",
    "chars": 3541,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2025-01-27'),\n"
  },
  {
    "path": "docs/guides/index.mdx",
    "chars": 825,
    "preview": "{\n  /**\n   * @import {Item} from '../_component/sort.js'\n   */\n\n  /**\n   * @typedef Props\n   * @property {Item} navigati"
  },
  {
    "path": "docs/guides/injecting-components.mdx",
    "chars": 3927,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2024-07-04'),\n"
  },
  {
    "path": "docs/guides/math.mdx",
    "chars": 3154,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/guides/mdx-on-demand.mdx",
    "chars": 3233,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/guides/syntax-highlighting.mdx",
    "chars": 4837,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/index.mdx",
    "chars": 3833,
    "preview": "import {Chart} from './_component/snowfall.jsx'\n\nexport {Home as default} from './_component/home.jsx'\nexport const info"
  },
  {
    "path": "docs/migrating/v1.mdx",
    "chars": 2448,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'johno', name: 'John Otander"
  },
  {
    "path": "docs/migrating/v2.mdx",
    "chars": 19580,
    "preview": "import {Note} from '../_component/note.jsx'\n\nexport const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/migrating/v3.mdx",
    "chars": 2871,
    "preview": "export const info = {\n  author: [\n    {github: 'wooorm', name: 'Titus Wormer'}\n  ],\n  modified: new Date('2023-10-24'),\n"
  },
  {
    "path": "docs/packages/index.mdx",
    "chars": 995,
    "preview": "{\n  /**\n   * @import {Item} from '../_component/sort.js'\n   */\n\n  /**\n   * @typedef Props\n   * @property {Item} navigati"
  },
  {
    "path": "docs/playground.mdx",
    "chars": 660,
    "preview": "export const info = {\n  author: [\n    {github: 'johno', name: 'John Otander'},\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "docs/table-of-components.mdx",
    "chars": 8535,
    "preview": "export const info = {\n  author: [\n    {github: 'johno', name: 'John Otander'},\n    {github: 'wooorm', name: 'Titus Worme"
  },
  {
    "path": "license",
    "chars": 1094,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor and Vercel, Inc.\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "package.json",
    "chars": 7782,
    "preview": "{\n  \"private\": true,\n  \"name\": \"monorepo\",\n  \"license\": \"MIT\",\n  \"homepage\": \"https://mdxjs.com\",\n  \"repository\": \"mdx-j"
  },
  {
    "path": "packages/esbuild/index.js",
    "chars": 114,
    "preview": "/**\n * @typedef {import('./lib/index.js').Options} Options\n */\n\nexport {esbuild as default} from './lib/index.js'\n"
  },
  {
    "path": "packages/esbuild/lib/index.js",
    "chars": 5853,
    "preview": "/**\n * @import {CompileOptions} from '@mdx-js/mdx'\n * @import {\n      Location,\n      Message,\n      OnLoadArgs,\n      O"
  },
  {
    "path": "packages/esbuild/license",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2021 Titus Wormer\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "packages/esbuild/package.json",
    "chars": 1392,
    "preview": "{\n  \"name\": \"@mdx-js/esbuild\",\n  \"version\": \"3.1.1\",\n  \"description\": \"esbuild plugin for MDX\",\n  \"license\": \"MIT\",\n  \"k"
  },
  {
    "path": "packages/esbuild/readme.md",
    "chars": 4566,
    "preview": "# `@mdx-js/esbuild`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badg"
  },
  {
    "path": "packages/esbuild/test/index.js",
    "chars": 17385,
    "preview": "/* eslint-disable unicorn/prefer-structured-clone */\n\n/**\n * @import {BuildFailure, Plugin} from 'esbuild'\n * @import {R"
  },
  {
    "path": "packages/esbuild/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/loader/index.cjs",
    "chars": 767,
    "preview": "/**\n * @import {LoaderContext} from 'webpack'\n * @import {Options as Options_} from './lib/index.js' with {'resolution-m"
  },
  {
    "path": "packages/loader/lib/index.js",
    "chars": 3670,
    "preview": "/**\n * @import {CompileOptions} from '@mdx-js/mdx'\n * @import {Compatible, VFile} from 'vfile'\n * @import {VFileMessage}"
  },
  {
    "path": "packages/loader/license",
    "chars": 1094,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor and Vercel, Inc.\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "packages/loader/package.json",
    "chars": 1648,
    "preview": "{\n  \"name\": \"@mdx-js/loader\",\n  \"version\": \"3.1.1\",\n  \"description\": \"Webpack loader for MDX\",\n  \"license\": \"MIT\",\n  \"ke"
  },
  {
    "path": "packages/loader/readme.md",
    "chars": 5642,
    "preview": "# `@mdx-js/loader`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge"
  },
  {
    "path": "packages/loader/test/index.js",
    "chars": 6758,
    "preview": "/**\n * @import {MDXContent} from 'mdx/types.js'\n */\n\nimport assert from 'node:assert/strict'\nimport fs from 'node:fs/pro"
  },
  {
    "path": "packages/loader/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/mdx/index.js",
    "chars": 861,
    "preview": "/**\n * @typedef {import('hast-util-to-jsx-runtime').Fragment} Fragment\n * @typedef {import('hast-util-to-jsx-runtime').J"
  },
  {
    "path": "packages/mdx/lib/compile.js",
    "chars": 1872,
    "preview": "/**\n * @import {Compatible, VFile} from 'vfile'\n * @import {ProcessorOptions} from './core.js'\n */\n\n/**\n * @typedef {Omi"
  },
  {
    "path": "packages/mdx/lib/core.js",
    "chars": 10214,
    "preview": "/**\n * @import {Program} from 'estree-jsx'\n * @import {Root} from 'mdast'\n * @import {Options as RehypeRecmaOptions} fro"
  },
  {
    "path": "packages/mdx/lib/evaluate.js",
    "chars": 2139,
    "preview": "/**\n * @import {MDXModule} from 'mdx/types.js'\n * @import {Compatible} from 'vfile'\n * @import {EvaluateOptions} from '."
  },
  {
    "path": "packages/mdx/lib/node-types.js",
    "chars": 296,
    "preview": "/**\n * List of node types made by `mdast-util-mdx`, which have to be passed\n * through untouched from the mdast tree to "
  },
  {
    "path": "packages/mdx/lib/plugin/recma-build-jsx-transform.js",
    "chars": 2360,
    "preview": "/**\n * @import {Program} from 'estree-jsx'\n */\n\n/**\n * @typedef Options\n *   Configuration for internal plugin `recma-bu"
  },
  {
    "path": "packages/mdx/lib/plugin/recma-document.js",
    "chars": 27620,
    "preview": "/**\n * @import {\n      CallExpression,\n      Directive,\n      ExportAllDeclaration,\n      ExportDefaultDeclaration,\n    "
  },
  {
    "path": "packages/mdx/lib/plugin/recma-jsx-rewrite.js",
    "chars": 19886,
    "preview": "/**\n * @import {\n      Expression,\n      Function as EstreeFunction,\n      Identifier,\n      ImportSpecifier,\n      JSXE"
  },
  {
    "path": "packages/mdx/lib/plugin/rehype-remove-raw.js",
    "chars": 609,
    "preview": "/**\n * @import {Root} from 'hast'\n */\n\nimport {visit} from 'unist-util-visit'\n\n/**\n * A tiny plugin that removes raw HTM"
  },
  {
    "path": "packages/mdx/lib/plugin/remark-mark-and-unravel.js",
    "chars": 3026,
    "preview": "/**\n * @import {Root, RootContent} from 'mdast'\n */\n\nimport {collapseWhiteSpace} from 'collapse-white-space'\nimport {wal"
  },
  {
    "path": "packages/mdx/lib/run.js",
    "chars": 1238,
    "preview": "/**\n * @import {MDXModule} from 'mdx/types.js'\n * @import {RunOptions} from './util/resolve-evaluate-options.js'\n */\n\n/*"
  },
  {
    "path": "packages/mdx/lib/types.d.ts",
    "chars": 1849,
    "preview": "import type {Program as EstreeProgram} from 'estree'\nimport type {Data as UnistData} from 'unist'\n\ninterface EsastData e"
  },
  {
    "path": "packages/mdx/lib/util/create-format-aware-processors.js",
    "chars": 2555,
    "preview": "/**\n * @import {Program} from 'estree-jsx'\n * @import {Root} from 'mdast'\n * @import {Processor} from 'unified'\n * @impo"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-create.js",
    "chars": 571,
    "preview": "/**\n * @import {Node} from 'estree-jsx'\n */\n\n// Fix to show references to above types in VS Code.\n''\n\n/**\n * @param {Rea"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-declaration-to-expression.js",
    "chars": 1022,
    "preview": "/**\n * @import {\n      Declaration,\n      Expression,\n      MaybeNamedClassDeclaration,\n      MaybeNamedFunctionDeclarat"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-is-declaration.js",
    "chars": 686,
    "preview": "/**\n * @import {\n      Declaration,\n      MaybeNamedClassDeclaration,\n      MaybeNamedFunctionDeclaration,\n      Node\n *"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-specifiers-to-declarations.js",
    "chars": 2917,
    "preview": "/**\n * @import {\n      AssignmentProperty,\n      ExportSpecifier,\n      Expression,\n      Identifier,\n      ImportDefaul"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-to-binary-addition.js",
    "chars": 565,
    "preview": "/**\n * @import {Expression} from 'estree-jsx'\n */\n\nimport {ok as assert} from 'devlop'\n\n/**\n * @param {ReadonlyArray<Exp"
  },
  {
    "path": "packages/mdx/lib/util/estree-util-to-id-or-member-expression.js",
    "chars": 1969,
    "preview": "/**\n * @import {\n      Identifier,\n      JSXIdentifier,\n      JSXMemberExpression,\n      Literal,\n      MemberExpression"
  },
  {
    "path": "packages/mdx/lib/util/extnames-to-regex.js",
    "chars": 390,
    "preview": "/**\n * Turn a list of extnames (*with* dots) into an expression.\n *\n * @param {ReadonlyArray<string>} extnames\n *   List"
  },
  {
    "path": "packages/mdx/lib/util/extnames.js",
    "chars": 158,
    "preview": "import markdownExtensions from 'markdown-extensions'\n\nexport const md = markdownExtensions.map(function (d) {\n  return '"
  },
  {
    "path": "packages/mdx/lib/util/resolve-evaluate-options.js",
    "chars": 3148,
    "preview": "/**\n * @import {Fragment, Jsx, JsxDev} from 'hast-util-to-jsx-runtime'\n * @import {MDXComponents} from 'mdx/types.js'\n *"
  },
  {
    "path": "packages/mdx/lib/util/resolve-file-and-options.js",
    "chars": 1314,
    "preview": "/**\n * @import {Compatible} from 'vfile'\n * @import {CompileOptions} from '../compile.js'\n * @import {ProcessorOptions} "
  },
  {
    "path": "packages/mdx/license",
    "chars": 1100,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor, Inc. and Vercel, Inc.\n\nPermission is hereby granted, free of charg"
  },
  {
    "path": "packages/mdx/package.json",
    "chars": 2992,
    "preview": "{\n  \"name\": \"@mdx-js/mdx\",\n  \"version\": \"3.1.1\",\n  \"description\": \"MDX compiler\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n  "
  },
  {
    "path": "packages/mdx/readme.md",
    "chars": 38139,
    "preview": "# `@mdx-js/mdx`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge]]["
  },
  {
    "path": "packages/mdx/test/compile.js",
    "chars": 42870,
    "preview": "/**\n * @import {Doctype, Element, Root} from 'hast'\n * @import {Root as MdastRoot} from 'mdast'\n * @import {MDXComponent"
  },
  {
    "path": "packages/mdx/test/context/components.js",
    "chars": 556,
    "preview": "/**\n * @import {ComponentProps} from 'react'\n */\n\nimport React from 'react'\n\n/**\n * @param {Readonly<ComponentProps<'spa"
  },
  {
    "path": "packages/mdx/test/context/data.js",
    "chars": 194,
    "preview": "/**\n * Number.\n */\nexport const number = 3.14\n\n/**\n * Object.\n */\nexport const object = {a: 1, b: 2}\n\n/**\n * Array.\n */\n"
  },
  {
    "path": "packages/mdx/test/context/run.js",
    "chars": 920,
    "preview": "/**\n * @import {MDXContent, MDXModule} from 'mdx/types.js'\n * @import {Compatible} from 'vfile'\n */\n\nimport fs from 'nod"
  },
  {
    "path": "packages/mdx/test/core.js",
    "chars": 424,
    "preview": "import assert from 'node:assert/strict'\nimport {test} from 'node:test'\n\ntest('@mdx-js/mdx: core', async function (t) {\n "
  },
  {
    "path": "packages/mdx/test/evaluate.js",
    "chars": 12063,
    "preview": "import assert from 'node:assert/strict'\nimport {test} from 'node:test'\nimport {evaluate, evaluateSync, compile} from '@m"
  },
  {
    "path": "packages/mdx/test/index.js",
    "chars": 136,
    "preview": "/* eslint-disable import-x/no-unassigned-import */\nimport './compile.js'\nimport './core.js'\nimport './evaluate.js'\nimpor"
  },
  {
    "path": "packages/mdx/test/syntax.js",
    "chars": 24862,
    "preview": "// Register directive nodes in mdast:\n/// <reference types=\"mdast-util-directive\" />\n\n/**\n * @import {Root as MdastRoot}"
  },
  {
    "path": "packages/mdx/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/node-loader/index.js",
    "chars": 367,
    "preview": "/**\n * @typedef {import('./lib/index.js').Options} Options\n */\n\nimport {createLoader} from './lib/index.js'\n\nconst defau"
  },
  {
    "path": "packages/node-loader/lib/condition.default.js",
    "chars": 33,
    "preview": "export const development = false\n"
  },
  {
    "path": "packages/node-loader/lib/condition.development.js",
    "chars": 32,
    "preview": "export const development = true\n"
  },
  {
    "path": "packages/node-loader/lib/index.js",
    "chars": 2926,
    "preview": "/**\n * @import {LoadFnOutput, LoadHook, LoadHookContext} from 'node:module'\n * @import {Process} from '@mdx-js/mdx/inter"
  },
  {
    "path": "packages/node-loader/license",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2021 Titus Wormer\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "packages/node-loader/package.json",
    "chars": 1502,
    "preview": "{\n  \"name\": \"@mdx-js/node-loader\",\n  \"version\": \"3.1.1\",\n  \"description\": \"Node.js loader for MDX\",\n  \"license\": \"MIT\",\n"
  },
  {
    "path": "packages/node-loader/readme.md",
    "chars": 5886,
    "preview": "# `@mdx-js/node-loader`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-"
  },
  {
    "path": "packages/node-loader/test/index.js",
    "chars": 2455,
    "preview": "/**\n * @import {MDXModule} from 'mdx/types.js'\n */\n\nimport assert from 'node:assert/strict'\nimport fs from 'node:fs/prom"
  },
  {
    "path": "packages/node-loader/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/preact/index.js",
    "chars": 61,
    "preview": "export {MDXProvider, useMDXComponents} from './lib/index.js'\n"
  },
  {
    "path": "packages/preact/lib/index.js",
    "chars": 2175,
    "preview": "/**\n * @import {MDXComponents} from 'mdx/types.js'\n * @import {Component, ComponentChildren, VNode} from 'preact'\n */\n\n/"
  },
  {
    "path": "packages/preact/license",
    "chars": 1094,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor and Vercel, Inc.\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "packages/preact/package.json",
    "chars": 1865,
    "preview": "{\n  \"name\": \"@mdx-js/preact\",\n  \"version\": \"3.1.1\",\n  \"description\": \"Preact context for MDX\",\n  \"license\": \"MIT\",\n  \"ke"
  },
  {
    "path": "packages/preact/readme.md",
    "chars": 6807,
    "preview": "# `@mdx-js/preact`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge"
  },
  {
    "path": "packages/preact/test/index.jsx",
    "chars": 5349,
    "preview": "/* @jsxRuntime automatic */\n/* @jsxImportSource preact */\n\n/**\n * @import {ComponentProps} from 'preact'\n */\n\nimport ass"
  },
  {
    "path": "packages/preact/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/react/index.js",
    "chars": 61,
    "preview": "export {MDXProvider, useMDXComponents} from './lib/index.js'\n"
  },
  {
    "path": "packages/react/lib/index.js",
    "chars": 2315,
    "preview": "/**\n * @import {MDXComponents} from 'mdx/types.js'\n * @import {Component, ReactElement, ReactNode} from 'react'\n */\n\n/**"
  },
  {
    "path": "packages/react/license",
    "chars": 1094,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor and Vercel, Inc.\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "packages/react/package.json",
    "chars": 1792,
    "preview": "{\n  \"name\": \"@mdx-js/react\",\n  \"version\": \"3.1.1\",\n  \"description\": \"React context for MDX\",\n  \"license\": \"MIT\",\n  \"keyw"
  },
  {
    "path": "packages/react/readme.md",
    "chars": 7099,
    "preview": "# `@mdx-js/react`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge]"
  },
  {
    "path": "packages/react/test/index.jsx",
    "chars": 5277,
    "preview": "/**\n * @import {ComponentProps} from 'react'\n */\n\nimport assert from 'node:assert/strict'\nimport {test} from 'node:test'"
  },
  {
    "path": "packages/react/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/remark-mdx/index.js",
    "chars": 168,
    "preview": "// Augment node types:\n/// <reference types=\"mdast-util-mdx\" />\n\n/**\n * @typedef {import('./lib/index.js').Options} Opti"
  },
  {
    "path": "packages/remark-mdx/lib/index.js",
    "chars": 1308,
    "preview": "/**\n * @import {ToMarkdownOptions} from 'mdast-util-mdx'\n * @import {Options as MicromarkOptions} from 'micromark-extens"
  },
  {
    "path": "packages/remark-mdx/license",
    "chars": 1099,
    "preview": "(The MIT License)\n\nCopyright (c) 2020 Titus Wormer <tituswormer@gmail.com>\n\nPermission is hereby granted, free of charge"
  },
  {
    "path": "packages/remark-mdx/package.json",
    "chars": 1469,
    "preview": "{\n  \"name\": \"remark-mdx\",\n  \"version\": \"3.1.1\",\n  \"description\": \"remark plugin to support MDX syntax\",\n  \"license\": \"MI"
  },
  {
    "path": "packages/remark-mdx/readme.md",
    "chars": 9391,
    "preview": "# remark-mdx\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge]][dow"
  },
  {
    "path": "packages/remark-mdx/test/index.js",
    "chars": 12320,
    "preview": "/**\n * @import {Nodes} from 'mdast'\n * @import {\n      MdxJsxAttribute,\n      MdxJsxAttributeValueExpression,\n      MdxJ"
  },
  {
    "path": "packages/remark-mdx/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/rollup/index.js",
    "chars": 113,
    "preview": "/**\n * @typedef {import('./lib/index.js').Options} Options\n */\n\nexport {rollup as default} from './lib/index.js'\n"
  },
  {
    "path": "packages/rollup/lib/index.js",
    "chars": 3104,
    "preview": "/**\n * @import {FormatAwareProcessors} from '@mdx-js/mdx/internal-create-format-aware-processors'\n * @import {CompileOpt"
  },
  {
    "path": "packages/rollup/license",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2021 Titus Wormer\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "packages/rollup/package.json",
    "chars": 1406,
    "preview": "{\n  \"name\": \"@mdx-js/rollup\",\n  \"version\": \"3.1.1\",\n  \"description\": \"Rollup plugin for MDX\",\n  \"license\": \"MIT\",\n  \"key"
  },
  {
    "path": "packages/rollup/readme.md",
    "chars": 5684,
    "preview": "# `@mdx-js/rollup`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge"
  },
  {
    "path": "packages/rollup/test/index.js",
    "chars": 3374,
    "preview": "/**\n * @import {MDXModule} from 'mdx/types.js'\n * @import {RollupOutput} from 'rollup'\n */\n\nimport assert from 'node:ass"
  },
  {
    "path": "packages/rollup/test/vite-entry.mdx",
    "chars": 13,
    "preview": "# Hello Vite\n"
  },
  {
    "path": "packages/rollup/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/vue/index.js",
    "chars": 61,
    "preview": "export {MDXProvider, useMDXComponents} from './lib/index.js'\n"
  },
  {
    "path": "packages/vue/lib/index.js",
    "chars": 1088,
    "preview": "/**\n * @import {MDXComponents} from 'mdx/types.js'\n * @import {Component, ComponentPublicInstance} from 'vue'\n */\n\n/**\n "
  },
  {
    "path": "packages/vue/license",
    "chars": 1100,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Compositor, Inc. and Vercel, Inc.\n\nPermission is hereby granted, free of charg"
  },
  {
    "path": "packages/vue/package.json",
    "chars": 1294,
    "preview": "{\n  \"name\": \"@mdx-js/vue\",\n  \"version\": \"3.1.1\",\n  \"description\": \"Vue provider for MDX\",\n  \"license\": \"MIT\",\n  \"keyword"
  },
  {
    "path": "packages/vue/readme.md",
    "chars": 5781,
    "preview": "# `@mdx-js/vue`\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge]]["
  },
  {
    "path": "packages/vue/test/index.js",
    "chars": 3723,
    "preview": "/**\n * @import {MDXModule} from 'mdx/types.js'\n * @import {Component} from 'vue'\n */\n\nimport assert from 'node:assert/st"
  },
  {
    "path": "packages/vue/tsconfig.json",
    "chars": 39,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "readme.md",
    "chars": 5875,
    "preview": "[![MDX][githubusercontent-logo]][website]\n\n# Markdown for the component era\n\n[![Build][build-badge]][build]\n[![Coverage]"
  },
  {
    "path": "renovate.json5",
    "chars": 92,
    "preview": "{\n  extends: ['config:base', ':preserveSemverRanges'],\n  schedule: 'before 3am on Monday'\n}\n"
  },
  {
    "path": "script/jsx-loader.js",
    "chars": 1034,
    "preview": "import fs from 'node:fs/promises'\nimport {fileURLToPath} from 'node:url'\nimport {transform} from 'esbuild'\n\nconst {load}"
  },
  {
    "path": "tsconfig.json",
    "chars": 697,
    "preview": "{\n  \"compilerOptions\": {\n    \"checkJs\": true,\n    \"customConditions\": [\"development\"],\n    \"declaration\": true,\n    \"dec"
  },
  {
    "path": "vercel.json",
    "chars": 4451,
    "preview": "{\n  \"public\": true,\n  \"trailingSlash\": true,\n  \"redirects\": [\n    {\n      \"destination\": \"/community/about/\",\n      \"sou"
  },
  {
    "path": "website/generate.js",
    "chars": 8666,
    "preview": "#!/usr/bin/env node\n/**\n * @import {Element, Properties, Root} from 'hast'\n * @import {MDXContent} from 'mdx/types.js'\n "
  },
  {
    "path": "website/mdx-loader.js",
    "chars": 12934,
    "preview": "/**\n * @import {CompileOptions} from '@mdx-js/mdx'\n * @import {Program} from 'estree'\n * @import {ElementContent, Root} "
  },
  {
    "path": "website/post.js",
    "chars": 10791,
    "preview": "/**\n * @import {Stats} from 'node:fs'\n * @import {DataMapMatter, DataMapMeta} from 'vfile'\n * @import {Entry} from 'xast"
  },
  {
    "path": "website/prep.js",
    "chars": 2635,
    "preview": "#!/usr/bin/env node\n/**\n * @import {Root} from 'hast'\n */\n\nimport fs from 'node:fs/promises'\nimport {fileURLToPath} from"
  },
  {
    "path": "website/schema-description.js",
    "chars": 418,
    "preview": "/**\n * @import {Schema} from 'hast-util-sanitize'\n */\n\n/**\n * @type {Readonly<Schema>}\n */\nexport const schema = {\n  anc"
  },
  {
    "path": "website/types.d.ts",
    "chars": 1243,
    "preview": "import type {Author} from './generate.js'\n\n// Register data on `estree`.\ndeclare module 'estree' {\n  interface BaseNode "
  }
]

About this extraction

This page contains the full source code of the mdx-js/mdx GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 167 files (689.2 KB), approximately 191.2k tokens, and a symbol index with 152 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!