How pi-web Renders Markdown with Mermaid Diagrams and KaTeX Math

pi-web processes user-generated markdown through a React-Markdown pipeline that chains remark plugins for parsing, rehype plugins for transformation, and custom components for rendering interactive Mermaid diagrams and KaTeX-styled mathematics.

The agegr/pi-web repository implements a sophisticated markdown processing system that extends standard React-Markdown capabilities to support technical documentation requirements. By combining specialized remark plugins, strict HTML sanitization, and lazy-loaded client-side rendering, the application safely transforms raw markdown strings into interactive documents featuring mathematical notation and flow diagrams.

The Markdown Rendering Pipeline

The entry point in components/MarkdownBody.tsx orchestrates the entire transformation process. It receives raw markdown content, normalizes LaTeX display delimiters using normalizeDisplayMath from lib/markdown.ts, and passes the processed string to the <ReactMarkdown> component with carefully configured plugin arrays.

Parsing with Remark Plugins

Before transformation begins, the pipeline applies remark plugins to parse GitHub-flavored markdown extensions and mathematical expressions.

GitHub-Flavored Markdown Support

The system incorporates remark-gfm to enable tables, task lists, strikethroughs, and other GitHub-specific syntax extensions. This allows content creators to use standard GitHub markdown features without additional configuration.

Math Detection with Remark-Math

The remark-math plugin identifies inline math delimiters (\(...\)) and display math blocks ($$...$$), converting them into proper AST nodes for downstream processing. This detection occurs early in the pipeline, ensuring mathematical content is properly isolated before HTML generation.

Transformation with Rehype Plugins

After parsing, the Abstract Syntax Tree passes through a series of rehype plugins defined in lib/markdown.ts and exported as markdownRehypePlugins. These plugins handle the final HTML generation and security sanitization.

HTML Sanitization

The rehype-sanitize plugin applies a custom schema that strictly whitelists code elements by language class while stripping unsafe HTML attributes and potentially malicious tags. The rehype-raw plugin enables controlled HTML passthrough within markdown documents, allowing embedded HTML only after sanitization checks.

KaTeX Math Rendering

The rehype-katex plugin transforms math nodes into static HTML using KaTeX. The required stylesheet is globally imported in app/layout.tsx via katex.min.css, ensuring consistent typography across the application. This server-side compatible rendering produces static HTML that requires no client-side JavaScript to display.

Handling Mermaid Diagrams

Unlike standard code blocks, Mermaid diagrams require special client-side handling and lazy loading to avoid bundling the heavy Mermaid library in the initial JavaScript payload.

Code Block Detection

Inside components/MarkdownBody.tsx, the component inspects fenced code block language identifiers. When the language equals mermaid, it renders the custom <MermaidBlock> component; otherwise, it uses the generic <CodeBlock> component. This branching logic ensures diagrams receive specialized handling while standard code blocks use the standard renderer.

Lazy Client-Side Rendering

components/MermaidBlock.tsx dynamically imports the Mermaid library only when a user requests a diagram preview, eliminating server-side bundle size penalties. The component initializes Mermaid with a theme matching the current UI (dark or default), parses the diagram source, and stores the resulting SVG in component state. Users interact with a preview button that opens a zoom-able dialog for full diagram inspection.

Theme Awareness

Both KaTeX mathematical styling and Mermaid diagram theming respond to the application's dark mode state through the useTheme hook. When users toggle between light and dark themes, mathematical equations update their color schemes automatically, and Mermaid re-renders diagrams with the appropriate color palette without requiring manual refresh or page reload.

Complete Implementation Example

Here is a practical implementation showing how to render markdown content with both mathematical expressions and diagrams:

import MarkdownBody from './components/MarkdownBody';

<MarkdownBody
  children={`

# Physics Documentation

The energy-mass equivalence is expressed as:

$$
E = mc^2
$$

Inline math example: \\( \\frac{d}{dx}f(x) \\)

System architecture:

\`\`\`mermaid
graph LR
    A[Client] --> B[Server]
    B --> C[Database]
\`\`\`
`}
  cwd="/home/user/project"
  onOpenFile={(path) => console.log('open', path)}
/>

The mermaid block renders as an interactive diagram preview, while the LaTeX equations display with proper KaTeX typography.

Summary

  • The MarkdownBody component in components/MarkdownBody.tsx serves as the primary entry point, normalizing LaTeX and coordinating React-Markdown with custom plugins.
  • Remark plugins (remark-gfm, remark-math) parse GitHub-flavored extensions and mathematical notation into AST nodes.
  • Rehype plugins (rehype-sanitize, rehype-katex, rehype-raw) sanitize HTML and convert math nodes into KaTeX-rendered HTML, with styles defined in app/layout.tsx.
  • Mermaid diagrams are handled specially in components/MermaidBlock.tsx through lazy-loaded client-side rendering with theme-aware SVG generation.
  • All mathematical and diagrammatic content automatically adapts to the application's dark mode setting via the useTheme hook.

Frequently Asked Questions

How does pi-web prevent XSS attacks when rendering raw markdown?

The pipeline implements a custom sanitization schema in lib/markdown.ts using rehype-sanitize, which strictly whitelists only safe HTML elements and specific code class attributes for syntax highlighting. Potentially dangerous tags and attributes are stripped before the content reaches the DOM, while rehype-raw allows controlled HTML passthrough under these constraints.

Why is Mermaid rendered client-side instead of server-side?

components/MermaidBlock.tsx dynamically imports the Mermaid library only when a user requests a diagram preview, eliminating server-side bundle size penalties. This approach keeps the initial page load lightweight while still supporting complex diagram interactions like zooming and theming.

What markdown extensions are supported beyond standard CommonMark?

The system supports GitHub-flavored markdown through remark-gfm, enabling tables, task lists, strikethroughs, and autolinks. Additionally, remark-math provides full support for LaTeX mathematical expressions using both inline \(...\) and display $$...$$ delimiters.

How does the application handle theme switching for mathematical content?

The KaTeX stylesheet imported in app/layout.tsx responds to the application's dark mode state managed by the useTheme hook. When the theme toggles between dark and default, both the mathematical notation and Mermaid diagrams automatically re-render with appropriate color schemes without requiring manual refresh.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →