Skip to content

MDX

MDX is Markdown + JSX, combining CommonMark prose with React component syntax. It is the standard format for documentation sites built with Next.js, Docusaurus, Astro, and similar frameworks.

Package: relational-text/mdxNamespace: dev.mdxjs.facet

Functions

ts
import { from, to } from 'relational-text/registry'

from('mdx', input: string): Document

Parse an MDX string into a RelationalText Document.

ts
const doc = from('mdx', `---
title: Hello
---

import { Button } from './Button'

# Heading

A paragraph with **bold** and *italic* text.

<Alert type="warning">
  Watch out!
</Alert>
`)

Supports:

  • YAML frontmatter (--- blocks) — each key stored as a frontmatter block with { key, value } attrs
  • Top-level import statements — stored as import-stmt blocks with { code } attr
  • JSX block elements (<Component>…</Component> or <Component />) — stored as jsx-block blocks
  • Inline JSX self-closing tags (<Tag />) — stored as jsx-inline entities
  • JS expressions ({expr}) — stored as expression entities
  • Standard CommonMark: headings, fenced code blocks, blockquotes, lists, horizontal rules, paragraphs
  • Inline marks: **strong**, *emphasis*, ~~strikethrough~~, `code`
  • Links [text](url) and images ![alt](src)

to('mdx', doc: Document): string

Render a RelationalText Document back to an MDX string.

ts
const mdx = to('mdx', doc)

Frontmatter blocks are collected and emitted as a contiguous YAML block at the top. Import blocks follow immediately after. JSX blocks are emitted as <Tag>…</Tag> or <Tag />. Everything else renders as standard CommonMark.

Automatically applies any registered lenses targeting dev.mdxjs.facet via lensGraph.autoTransform().

ensureMDXLexicon(): void

Explicitly register the MDX lexicon. Called automatically by from('mdx', ...) / to('mdx', ...) on first use. Safe to call multiple times.

Feature Mapping

Inline Marks

MDX syntaxFeature nameRT hub name
**text**strongbold
*text*emphasisitalic
~~text~~strikethroughstrikethrough
`code`code-spancode
[text](url)linklink
![alt](src)imageimage
<Tag /> (inline)jsx-inline
{expr}expression

Block Elements

MDX syntaxFeature nameAttrs
# … ######heading{ level: 1–6 }
```langcode-block{ language?: string }
> textblockquote-marker
- text / * textbullet-list-marker / list-item-text
1. textordered-list-marker / list-item-text
---horizontal-rule
key: value (frontmatter)frontmatter{ key, value }
import …import-stmt{ code }
<Tag>…</Tag>jsx-block{ tag, selfClosing?, props?, content? }

Examples

Import

ts
import { from } from 'relational-text/registry'

const doc = from('mdx', `---
title: My Post
date: 2024-01-01
---

import { Callout } from './components'

## Introduction

This is a **paragraph** with a [link](https://example.com).
`)

console.log(doc.text)
// "\uFFFCMy Post\n2024-01-01\nIntroduction\nThis is a paragraph with a link."

Export

ts
import { from, to } from 'relational-text/registry'

const doc = from('markdown', '## Heading\n\n**bold** and _italic_')
const mdx = to('mdx', doc)
// "## Heading\n\n**bold** and *italic*"

Cross-format

ts
import { from, to } from 'relational-text/registry'

const doc = from('mdx', '# Title\n\nHello **world**.')
const html = to('html', doc)
// '<h1>Title</h1>\n<p>Hello <strong>world</strong>.</p>\n'

Notes

  • JSX block detection uses uppercase-first tag names as a heuristic (<Button> is JSX, <div> is HTML). Lowercase custom elements are not detected as JSX blocks.
  • YAML frontmatter is parsed as flat key: value lines. Nested YAML structures are not supported.
  • import statements must start at the beginning of a line (no leading whitespace).
  • MDX-specific features (jsx-block, jsx-inline, expression, frontmatter, import-stmt) have no RT hub equivalents and are silently dropped in cross-format conversions that don't support them.
  • The mdx-to-relationaltext lens maps strongbold, emphasisitalic, strikethroughstrikethrough, linklink, headingheading, etc.