remark plugin to parse and stringify math expressions using LaTeX-style syntax with dollar delimiters
npx @tessl/cli install tessl/npm-remark-math@6.0.0remark-math is a unified remark plugin that extends markdown parsing and serialization to support mathematical expressions using LaTeX-style syntax with dollar delimiters ($..$ for inline and $$...$$ for block math). It integrates seamlessly with the unified ecosystem, particularly remark-rehype for HTML transformation, converting math nodes into properly structured HTML elements with appropriate CSS classes for downstream rendering by KaTeX, MathJax, or other math rendering engines.
npm install remark-mathimport remarkMath from 'remark-math';For TypeScript projects:
import remarkMath from 'remark-math';
// Note: Options type is available via JSDoc but not as named exportFor CommonJS environments (though package is ES Module only):
const remarkMath = require('remark-math').default;import rehypeKatex from 'rehype-katex';
import rehypeStringify from 'rehype-stringify';
import remarkMath from 'remark-math';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import {unified} from 'unified';
const processor = unified()
.use(remarkParse)
.use(remarkMath)
.use(remarkRehype)
.use(rehypeKatex)
.use(rehypeStringify);
const markdown = `
Lift ($C_L$) can be determined by the following equation:
$$
L = \\frac{1}{2} \\rho v^2 S C_L
$$
`;
const result = await processor.process(markdown);
console.log(String(result));remark-math follows the unified plugin architecture:
micromark-extension-math for low-level parsingmdast-util-math for AST transformationinlineMath and math nodes in the MDAST syntax treeThe main plugin function that adds math support to unified processors.
/**
* Add support for math expressions in markdown
* @param {Options | null | undefined} [options] - Configuration options
* @returns {undefined} - Returns nothing, modifies processor in place
*/
function remarkMath(options?: Options): undefined;Usage Example:
import remarkMath from 'remark-math';
import {unified} from 'unified';
import remarkParse from 'remark-parse';
const processor = unified()
.use(remarkParse)
.use(remarkMath, { singleDollarTextMath: false });interface Options {
/**
* Whether to support text math (inline) with a single dollar
* Single dollars work in Pandoc but often interfere with normal dollars in text
* @default true
*/
singleDollarTextMath?: boolean;
}Configuration Examples:
// Default behavior - single dollar inline math enabled
.use(remarkMath)
// Disable single dollar inline math (only $$ works for inline)
.use(remarkMath, { singleDollarTextMath: false })$expression$ (configurable, enabled by default)$$expression$$ (always supported)The formula $E = mc^2$ shows mass-energy equivalence.$$\nexpression\n$$ (on separate lines)$$
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
$$\\$ prevents math parsingcode blocks are ignoredThe price is \\$5.99 (not math)
`$variable` in code (not math)When used with remark-rehype, math nodes are converted to HTML with semantic CSS classes:
<code class="language-math math-inline">E = mc^2</code><pre><code class="language-math math-display">\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}</code></pre>These HTML structures are designed to work with:
.language-math classesremark-math handles malformed math gracefully:
$$ with no content ignoredThe plugin creates two new MDAST node types:
interface InlineMath {
type: 'inlineMath';
value: string;
data?: {
hName: 'code';
hProperties: {
className: ['language-math', 'math-inline'];
};
hChildren: Array<{ type: 'text'; value: string }>;
};
}interface Math {
type: 'math';
value: string;
meta: null;
data?: {
hName: 'pre';
hChildren: Array<{
type: 'element';
tagName: 'code';
properties: {
className: ['language-math', 'math-display'];
};
children: Array<{ type: 'text'; value: string }>;
}>;
};
}