latex
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Mar 17, 2026

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#

import "katex/dist/katex.min.css"; // [!code ++]

Update markdown-text.tsx#

import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";
import remarkMath from "remark-math"; // [!code ++]
import rehypeKatex from "rehype-katex"; // [!code ++]

const MarkdownTextImpl = () => {
  return (
    <MarkdownTextPrimitive
      remarkPlugins={[remarkGfm, remarkMath]} // add remarkMath // [!code ++]
      rehypePlugins={[rehypeKatex]} // add rehypeKatex // [!code ++]
      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:

import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";

const MarkdownTextImpl = () => {
  return (
    <MarkdownTextPrimitive
      remarkPlugins={[remarkGfm, remarkMath]}
      rehypePlugins={[rehypeKatex]}
      preprocess={normalizeCustomMathTags} // [!code ++]
      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.