logoassistant-ui

LaTeX

Render LaTeX mathematical expressions in chat messages using KaTeX.

LaTeX rendering is not enabled in markdown by default.

Install dependencies

npm i katex rehype-katex remark-math

Add KaTeX CSS to your layout

/app/layout.tsx
import "katex/dist/katex.min.css";

Update markdown-text.tsx

/components/assistant-ui/markdown-text.tsx
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";

const MarkdownTextImpl = () => {
  return (
    <MarkdownTextPrimitive
      remarkPlugins={[remarkGfm, remarkMath]} // add remarkMath
      rehypePlugins={[rehypeKatex]}           // add rehypeKatex
      className="aui-md"
      components={defaultComponents}
    />
  );
};

export const MarkdownText = memo(MarkdownTextImpl);

Supported Formats

By default, remark-math supports:

  • $...$ for inline math
  • $$...$$ for display math
  • Fenced code blocks with the math language identifier

Supporting Alternative LaTeX Delimiters

Many language models generate LaTeX using different delimiter formats:

  • \(...\) for inline math
  • \[...\] for display math
  • Custom formats like [/math]...[/math]

You can use the preprocess prop to normalize these formats:

/components/assistant-ui/markdown-text.tsx
const MarkdownTextImpl = () => {
  return (
    <MarkdownTextPrimitive
      remarkPlugins={[remarkGfm, remarkMath]}
      rehypePlugins={[rehypeKatex]}
      preprocess={normalizeCustomMathTags}
      className="aui-md"
      components={defaultComponents}
    />
  );
};

// Your LaTeX preprocessing function
function normalizeCustomMathTags(input: string): string {
  return (
    input
      // Convert [/math]...[/math] to $$...$$
      .replace(/\[\/math\]([\s\S]*?)\[\/math\]/g, (_, content) => `$$${content.trim()}$$`)

      // Convert [/inline]...[/inline] to $...$
      .replace(/\[\/inline\]([\s\S]*?)\[\/inline\]/g, (_, content) => `$${content.trim()}$`)

      // Convert \( ... \) to $...$ (inline math) - handles both single and double backslashes
      .replace(/\\{1,2}\(([\s\S]*?)\\{1,2}\)/g, (_, content) => `$${content.trim()}$`)

      // Convert \[ ... \] to $$...$$ (block math) - handles both single and double backslashes
      .replace(/\\{1,2}\[([\s\S]*?)\\{1,2}\]/g, (_, content) => `$$${content.trim()}$$`)
  );
}

The preprocessing function runs before markdown parsing, allowing you to transform any delimiter format into the standard $ and $$ format.