MDX.org.ai
UI ComponentsmdxuiRenderers

@mdxui/html

Render MDX to HTML

@mdxui/html

Render MDX documents to static HTML.

Installation

npm install @mdxui/html

Usage

import { renderToHTML } from '@mdxui/html'
 
const mdx = `
# Hello World
 
This is **bold** text.
`
 
const html = await renderToHTML(mdx)
// <h1>Hello World</h1>
// <p>This is <strong>bold</strong> text.</p>

Configuration

interface HTMLRenderOptions {
  /** Custom components */
  components?: Record<string, HTMLComponent>
 
  /** CSS class names */
  classNames?: Record<string, string>
 
  /** Inline styles */
  styles?: Record<string, CSSProperties>
 
  /** ID prefix for headings */
  idPrefix?: string
 
  /** Generate wrapper element */
  wrapper?: string | false
 
  /** Plugins */
  plugins?: Plugin[]
}

Features

Custom Components

import { renderToHTML, registerComponent } from '@mdxui/html'
 
registerComponent('Callout', ({ type, title, children }) => `
  <aside class="callout callout-${type}">
    ${title ? `<h4>${title}</h4>` : ''}
    <div>${children}</div>
  </aside>
`)
 
const html = await renderToHTML(`
<Callout type="warning" title="Caution">
  Be careful with this operation.
</Callout>
`)

CSS Classes

const html = await renderToHTML(mdx, {
  classNames: {
    h1: 'text-4xl font-bold tracking-tight',
    h2: 'text-3xl font-semibold mt-8 mb-4',
    p: 'text-gray-700 leading-relaxed mb-4',
    a: 'text-blue-600 hover:underline',
    ul: 'list-disc list-inside space-y-2',
    ol: 'list-decimal list-inside space-y-2',
    blockquote: 'border-l-4 border-gray-300 pl-4 italic',
    code: 'bg-gray-100 px-1 py-0.5 rounded text-sm',
    pre: 'bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto',
  },
})

Syntax Highlighting

import { renderToHTML, highlightPlugin } from '@mdxui/html'
 
const html = await renderToHTML(mdx, {
  plugins: [
    highlightPlugin({
      theme: 'github-dark',
      languages: ['javascript', 'typescript', 'bash'],
    }),
  ],
})

Heading IDs

const html = await renderToHTML(mdx, {
  idPrefix: 'content-',
})
 
// # Getting Started
// becomes:
// <h1 id="content-getting-started">Getting Started</h1>

Wrapper Element

const html = await renderToHTML(mdx, {
  wrapper: 'article',
  classNames: {
    wrapper: 'prose prose-lg max-w-none',
  },
})
// <article class="prose prose-lg max-w-none">...</article>

Examples

Email Template

import { renderToHTML } from '@mdxui/html'
 
const emailHTML = await renderToHTML(newsletter, {
  styles: {
    h1: { fontSize: '24px', color: '#333', marginBottom: '16px' },
    p: { fontSize: '16px', lineHeight: '1.6', color: '#555' },
    a: { color: '#0066cc' },
  },
  wrapper: 'div',
  classNames: {
    wrapper: 'email-body',
  },
})

Blog Post

import { renderToHTML, highlightPlugin, tocPlugin } from '@mdxui/html'
 
const { html, toc } = await renderToHTML(post, {
  plugins: [
    highlightPlugin({ theme: 'github-light' }),
    tocPlugin({ maxDepth: 3 }),
  ],
  classNames: {
    h1: 'text-4xl font-bold mb-6',
    h2: 'text-2xl font-semibold mt-8 mb-4',
    p: 'mb-4 leading-7',
  },
})

Documentation Page

const html = await renderToHTML(docs, {
  components: {
    Tabs: renderTabs,
    Tab: renderTab,
    Callout: renderCallout,
    CodeBlock: renderCodeBlock,
  },
  classNames: {
    h1: 'scroll-m-20 text-4xl font-extrabold tracking-tight',
    h2: 'scroll-m-20 border-b pb-2 text-3xl font-semibold',
  },
})

Server Integration

Express

import express from 'express'
import { renderToHTML } from '@mdxui/html'
 
const app = express()
 
app.get('/docs/:slug', async (req, res) => {
  const mdx = await loadContent(req.params.slug)
  const html = await renderToHTML(mdx)
 
  res.type('html').send(`
    <!DOCTYPE html>
    <html>
      <head><title>Docs</title></head>
      <body>${html}</body>
    </html>
  `)
})

Static Generation

import { renderToHTML } from '@mdxui/html'
import { glob } from 'glob'
 
const files = await glob('content/**/*.mdx')
 
for (const file of files) {
  const mdx = await readFile(file, 'utf-8')
  const html = await renderToHTML(mdx)
 
  const outPath = file
    .replace('content/', 'dist/')
    .replace('.mdx', '.html')
 
  await writeFile(outPath, wrapInLayout(html))
}

Streaming

import { renderToHTMLStream } from '@mdxui/html'
 
app.get('/stream/:slug', async (req, res) => {
  const mdx = await loadContent(req.params.slug)
  const stream = await renderToHTMLStream(mdx)
 
  res.type('html')
  stream.pipe(res)
})

On this page