KaTeX:<math/>
KaTeX is a LaTeX math renderer for the browser at 100× MathJax speed. Started inside Khan Academy in 2013, open-sourced in 2014. Returns an HTML string synchronously, renders an equation in ~1ms, caches a 250KB bundle once. Every equation on this page (the one below included) is live KaTeX — see /code/language/latex for the LaTeX it implements a subset of.
Emily Eisenberg + Sophie Alpert
synchronous, no layout shift
"equations you see in papers"
vs MathJax ~1.6MB
What is KaTeX
KaTeX = a browser-side LaTeX math renderer from Khan Academy, MIT-licensed, written in TypeScript. Not a full LaTeX engine — math mode only: no \documentclass, no TikZ, no page layout. But it covers 90%+ of the math that shows up in real papers, and returns HTML synchronously — no FOUC, no layout shift.
Math mode only. No \documentclass, TikZ, BibTeX, or page layout. A design choice, not a defect — tight scope is the only way you get 250KB in the browser. For the full LaTeX story see /code/language/latex.
renderToString(src) returns an HTML string immediately. No async, no promise, no font-load callback. First-class SSG / SSR citizen; no client-side flash. A different world from MathJax's async-everything model.
Default path is HTML elements + CSS positioning; the browser reuses its text rendering pipeline. Optional MathML overlay (output: 'htmlAndMathml') for a11y. Different from MathJax's default SVG path — one of the reasons it's fast.
Doesn't require native MathML support — so Chrome / Safari / Firefox render pixel-identically. MathML Core only stabilised in 2023 and cross-engine differences remain large; KaTeX owns its rendering = looks the same everywhere.
<script src="mathjax.js"></script>
<p>$\sum_{i=1}^n i$</p>
// load: 1.6MB
// parse + render: async
// font measurement: async
// result: equation arrives late, page jumps
// ~30ms / equation (v2)
// ~7–15ms / equation (v3)<link rel="stylesheet" href="katex.min.css">
<script>
const html = katex.renderToString(
'\\sum_{i=1}^n i'
); // returns string instantly
</script>
// load: 250KB (cached once)
// render: ~1ms, sync
// result: equation lands with HTML, zero jumpHistory : 1977 → 2026
KaTeX's arc breaks into four phases: the TeX/LaTeX ancestors (1977–2003) → the jsMath / MathJax era (2003–2013) → Khan Academy starts it + open-sources it (2013–2018) → mainstream adoption + the AI era (2019–2026). The full upstream LaTeX story is at /code/language/latex.
- 1977~1985
TeX → LaTeX — KaTeX's ancestors
Donald Knuth wrote TeX in 1977; Leslie Lamport built LaTeX as macros on top in 1985. KaTeX implements exactly the LaTeX math subset. The full story lives at /code/language/latex.
- 2003
jsMath — the first browser TeX
Davide Cervone (Union College) writes jsMath — the first serious attempt to put LaTeX math in the browser. GIF fallbacks, Adobe AFM fonts converted to TrueType — slow and ugly, but it opens the road for "math in the browser".
- 2009·08
MathJax 1.0 — the gold standard
Davide Cervone teams up with AMS / Design Science / SIAM and ships MathJax. Pure-JS, cross-browser, HTML+CSS / SVG / MathML output, auto font loading. For seven years almost every equation on the academic web is MathJax. But heavy: ~1.6MB default bundle, async parse + render, layout shift on long pages.
- 2010
Khan Academy takes off — math video on the web
Sal Khan's thousands of math problems from YouTube migrate into a web app. Early KA renders math via pre-rendered images or MathJax — a single practice page can carry hundreds of equations, and MathJax render time becomes student wait time. The pain that begets KaTeX gets buried here.
- 2013·09
KaTeX is born inside Khan Academy
Emily Eisenberg + Sophie Alpert (Sophie later joined Facebook's React core team) start it inside KA. The stated goal is blunt: "render math 100× faster than MathJax". The key insight: precompute font metrics at build time, never measure at runtime.
- 2014·09
Open-sourced + the Pre-Stash technique
KaTeX hits GitHub under MIT. "Pre-Stash" becomes the project's engineering shorthand — a ~30KB font-metric JSON ships inside the bundle so rendering is synchronous, ~1ms per equation, no FOUC, no layout shift. The first math renderer fast enough to be enjoyable on a long page.
- 2014
Stack Exchange Math evaluates it
The Mathematics Stack Exchange starts looking at KaTeX as a MathJax replacement. The eventual answer is both: KaTeX for simple expressions, MathJax fallback when KaTeX can't parse it. A hybrid pattern that several academic sites copy through 2014–2018.
- 2015
0.5 — matrices, aligned, colour
KaTeX 0.5 lands
\begin{aligned},\begin{pmatrix},\color. Real-world coverage of "equations you'd see in a paper" jumps from ~60% to ~80%; every release after that fills out more of the LaTeX math subset. - 2016
Discourse adopts KaTeX as default
Jeff Atwood's Discourse (the modern forum platform) switches its default math renderer to KaTeX from MathJax. Discourse owns the forum / community niche; once it flips, every open-source knowledge base on Discourse inherits KaTeX's speed.
- 2017
GitHub adds math → switches to KaTeX
GitHub adds math rendering to issues / PRs / READMEs. The first cut uses MathJax; GitHub later switches to KaTeX for both perf and bundle. From that point developers writing READMEs can drop
$\int$and get a real equation — a doc-habit shift across thousands of repos. - 2017
0.9 — the auto-render extension
Adds
renderMathInElement(): scan DOM text nodes, find$...$,$$...$$,\(...\)delimiters and replace in place. "Add KaTeX to your existing markdown site in one line" starts here. - 2018
0.10 — mhchem / copy-tex / MathML
Three big additions in one cut: mhchem (chemistry like
\ce{H_2O}), copy-tex (right-click a rendered equation, copy back the LaTeX source), and a MathML output mode for screen readers and accessibility. From here KaTeX is "good enough" for almost any teaching / explainer use case. - 2019
0.11 — full Unicode math mode
Direct parsing of Unicode math like
α,∑,∫(no need to type\alphafirst). Aligns KaTeX with consumer apps like Notion / Substack / Quora where users paste Unicode directly. - 2020~22
Notion / Substack / Quora all flip to KaTeX
Three big consumer platforms move within months of each other. The consumer-side "browser math" war is over: speed-first picks KaTeX, accessibility-first sticks with MathJax. They stop competing and each owns its lane. Hashnode, Roam, Logseq follow in the same window.
- 2022
GitHub-Flavored Markdown specs math
GFM spells out
$inline$and$$display$$as math syntax; the renderer is KaTeX. "Drop an equation into your README" shifts from convention to spec — reach: every open-source project on GitHub. - 2023
0.16 — ESM + perf refactor
Codebase moves to TypeScript, switches to ESM modules, parser is rewritten, render goes another notch faster. "Already fast enough" projects still squeezing perf — a sign of maturity, not decline.
- 2024
Obsidian / Logseq / every note app
Note-taking apps fully embrace KaTeX: Obsidian, Logseq, Anytype, Tana, Reflect. The same equation travels from notebook to blog to GitHub README rendered by the same engine — KaTeX is the browser-side lingua franca of LaTeX math.
- 2025
Maintenance mode + usage explosion
KaTeX 0.16.x is in steady maintenance: occasional bug fixes, occasional edge LaTeX commands; no more big swings. Usage keeps climbing though — LLMs emit LaTeX, the browser renders it via KaTeX, AI chat UIs push KaTeX to all-time highs.
- 2026
KaTeX in 2026 — the default browser math
2026: KaTeX is the default browser math renderer. MathJax is alive but holds only the a11y / full-LaTeX market. This very page renders with it — see in the hero.
The Pre-Stash Technique : Why100x
KaTeX outruns MathJax by 10–100×, not from a clever algorithm, but from a single engineering call: precompute font metrics at build time, never measure them at runtime. The decision has a name: "Pre-Stash."
Why MathJax is slow
Rendering an equation requires knowing the width / height / side-bearings of every glyph — where to put the fraction bar, what to line super/subscripts against, how big to draw the root sign all depend on these numbers.
MathJax's approach: at runtime, drop the character into a hidden div and read getBoundingClientRect(). Every measurement triggers real layout, forcing reflow. A long equation does it hundreds of times, a page thousands — async, slow, jittery.
- ~30ms per equation (v2) / ~7-15ms (v3)
- Async: equations arrive late, page jumps
- Shows
$ raw $until fonts arrive
KaTeX's answer
At build time KaTeX extracts every glyph metric out of the TeX .tfm files, serialises it into fontMetricsData.js (~30KB) and bundles it directly.
At runtime KaTeX looks up the JSON, never the DOM. No reflow, no async font load, no getBoundingClientRect. Pure computation, output is an HTML string. 1ms per equation.
- ~1ms per equation — 100× MathJax v2, 10× v3
- Sync: equation lands with HTML, zero layout shift
- Trade-off: locked to the bundled KaTeX fonts, no swap
// build-time (inside KaTeX source)
import { parseTfm } from './tfm-parser';
const metrics = {
"Main-Regular": parseTfm('cmr10.tfm'),
"Math-Italic": parseTfm('cmmi10.tfm'),
// ... 16 KaTeX_* fonts, thousands of glyphs each
};
writeFileSync('fontMetricsData.js', `export default ${JSON.stringify(metrics)}`);
// runtime (in the browser)
import metrics from './fontMetricsData'; // instantly available
function getCharMetric(font, ch) {
return metrics[font][ch.charCodeAt(0)];
}
// no DOM, no reflow, no font awaitIn one line: Pre-Stash is not algorithmic cleverness — it's moving the asynchrony into the build step. "Measure fonts in the user's browser" becomes "we already measured them before shipping". Same work, different point in time, and you go from 30ms async to 1ms sync. A textbook engineering trade-off.
Live Playground : KaTeXLive
Type LaTeX on the left and see live KaTeX rendering on the right (same engine as the rest of this page). What you type is what you render, synchronous, no await. Click a preset above for a classic.
LaTeX Coverage Matrix : Whatsupported
KaTeX implements 90%+ of LaTeX math mode. The left column is supported (with live rendered samples); the right is not supported (with the reason why). Every left-side sample is real live KaTeX.
\frac\sum / integrals \intpmatrix / bmatrixaligned / cases\mathbb\mathcal \mathfrak\binom / root \sqrt\overbrace\xrightarrow\begin{array}\cemacros option\documentclass / page setupKaTeX renders math, not documents\section / \chapterUse HTML <h1>–<h6>\newcommand auto-loadmacros exist, but must be passed explicitlyeqnarrayLong deprecated anyway, use alignedPerformance vs MathJax : Numbers
Two axes: per-equation render time and bundle size. Numbers composite KaTeX's own benchmark, MathJax's official benchmark, and multiple 2024–25 blog measurements; device = mid-range laptop Chrome main thread. The gap is orders of magnitude, not factors.
Per-equation render time (lower is better)
x-axis normalised against ~50ms max · sourced from public benchmarks
Bundle size (lower is better)
gzipped total · x-axis 100% = ~1.6MB MathJax default bundle
"KaTeX's goal is fast. Every design decision is bent toward "the user sees every equation on a long page instantly": synchronous, no font loading, no reflow. Fast math, not all math.
In one line: KaTeX isn't algorithmically faster than MathJax — it chose not to do certain things (don't measure fonts, don't go async, don't render non-math). The speed comes from doing less, not from a trick. 10× isn't magic — it's determined by scope.
API Surface : TheCallSites
KaTeX's API is small enough to read in one glance: two main entries (renderToString / render), plus four contrib extensions (auto-render / mhchem / copy-tex / etc.) and a few wrapper libraries. The eight cards below cover 95% of real usage.
katex.renderToString()
Synchronous, returns an HTML string. Top pick for SSR / static generation — bake the output into HTML, ship zero JS to the client.
import katex from 'katex';
const html = katex.renderToString(
'\\sum_{i=1}^n i^2',
{ displayMode: true }
);
// → <span class="katex-display">...</span>katex.render()
Client-side: mutates a DOM node in place. No return value, side-effect rendering. Pairs with React effects / framework directives.
const el = document.getElementById('eq');
katex.render('E = mc^2', el, {
throwOnError: false,
errorColor: '#FF8E72'
});The auto-render extension
One-line integration for legacy markdown / blog sites. Scans the DOM for $...$, $$...$$ and replaces in place.
import renderMathInElement from
'katex/contrib/auto-render';
renderMathInElement(document.body, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '$', right: '$', display: false }
]
});React wrapper
react-katex: <BlockMath> / <InlineMath>. This page uses useMemo + dangerouslySetInnerHTML directly — no extra dependency.
import { BlockMath } from 'react-katex';
<BlockMath
math={'\\int_0^1 x^2\\,dx'}
/>mhchem chemistry
Speaks the \ce{...} syntax. Required for teaching / chemistry sites.
import 'katex/contrib/mhchem';
katex.renderToString(
'\\ce{2H2 + O2 -> 2H2O}'
);copy-tex
Right-click and copy a rendered equation and your clipboard holds the LaTeX source, not the rendered HTML. Essential for academic / note workflows.
import 'katex/contrib/copy-tex';
// ↑ that's it. side-effect import.SSR pipeline
SSG / SSR: call renderToString at build time → bake the HTML + katex.min.css into the page → client never loads KaTeX JS. This site's prediction long-form pages run exactly this way.
// build.ts
const body = mdAst.walk((eq) =>
katex.renderToString(eq.src)
);
writeFile('out.html', body);Error handling
throwOnError: false + errorColor = broken equations turn into red fallback text instead of crashing the page. Rule one for production.
katex.renderToString(input, {
throwOnError: false,
errorColor: '#FF8E72',
strict: 'ignore'
});SSR best practice
At build time render all equations and bake them into the HTML; the client only needs to link katex.min.css (~23KB). The KaTeX JS never has to ship to the client — that's exactly how the prediction long-form pages on this site work, and LCP benefits directly.
"The best client-side JS is JS you never ship. — Alex Russell (frequently quoted)"
KatexOptions Cookbook : Recipes
Every render / renderToString call takes a KatexOptions object. The 12 below are the ones real projects actually tweak, grouped by purpose.
Ecosystem / Users / Tools : Ecosystem
2026 KaTeX users in production: GitHub, Notion, Discourse, Stack Exchange, Obsidian, Substack, Khan Academy, Quora, Logseq, Hashnode, Roam Research, every modern static-site generator (Hugo / Astro / Eleventy / Docusaurus / VitePress). The 12 cards below cover tools, wrappers and upstream / downstream anchors. Upstream LaTeX at /code/language/latex.
vs MathJax : TheRivalry
KaTeX and MathJax aren't the same product: one chases speed, the other chases full LaTeX + accessibility. Since 2020 they each own a lane and stopped competing head-on. The table below is honest, not a KaTeX victory lap.
| KaTeX | MathJax v3 | Note | |
|---|---|---|---|
| Speed (per eq) | ~1ms sync | ~7-15ms async, sync optional | KaTeX 10× |
| Bundle size | ~250KB gzipped | ~1.6MB / ~560KB lazy | KaTeX 6× |
| LaTeX coverage | ~90% of the math subset | Near-complete LaTeX math + packages | MathJax wins |
| Accessibility | HTML+CSS / optional MathML | Native MathML, perfect SR support | MathJax wins |
| Output format | HTML+CSS (default) | SVG / MathML / HTML+CSS | MathJax: more outputs |
| SSR | Sync from day one | Only v3 added sync API | KaTeX wins |
| Fonts | Locked to KaTeX_* (Pre-Stash) | Any font, swappable | MathJax: flexible |
| Cross-browser identical | Pixel-identical | Differs in native MathML mode | KaTeX wins |
| License | MIT | Apache 2.0 | Both commercial-friendly |
| Release cadence | Maintenance (yearly) | Active (quarterly) | MathJax: bigger team |
| Primary users | Consumer: GitHub / Notion / Substack / note apps / AI chat | Academic: arXiv / publishers / journals / a11y-first | Different niches |
| 2026 direction | AI chat UI default · steady | Holding academia / a11y | No longer competing |
Why KaTeX in 2026 : PickKaTeX
"Legacy tech" is the standard KaTeX misconception — 2024–2026 it had a usage explosion driven by AI chat UIs. Six cards on why it's still the right pick in 2026.
Synchronous render = zero layout shift
renderToString returns finished HTML. Unlike MathJax's async font measurement, long math-heavy pages don't jump around. CLS score goes straight to perfect.
katex.renderToString(src) // → instant string
// MathJax v2 was async, layout shifts when fonts arrive~250KB, cached once
JS + CSS + KaTeX_* fonts together come to ~250KB gzipped, cached across pages. MathJax v3's full bundle is ~1.6MB — over 6× larger. An entire LCP tier on mobile.
// katex.min.css ≈ 23KB gzip
// katex.min.js ≈ 72KB gzip
// fonts/* ≈ 150KB gzip (woff2)TypeScript + ESM + MIT
Post-0.16 the whole codebase is TS, with types shipped, ESM modules. License is MIT — commercial, teaching, closed-source: zero friction. Hits every 2026 "modern engineering" checkbox.
import katex, { KatexOptions } from 'katex';
// types ship with the package, no @types/* needed for optsThe "just enough" 90%
No TikZ, no BibTeX, no page layout — focus on LaTeX math, full stop. The result: 90%+ of real-world equations parse out of the box, the remaining 10% mostly covered by mhchem / macros. Tight scope, easier engineering.
// scope = math mode + AMS + a few envs
// not = a whole TeX engine in JSSSR as a first-class citizen
renderToString was synchronous from day one — meaning SSG / SSR work without contortions: bake HTML at build, ship zero KaTeX JS to the client, only ~23KB of CSS.
// build step:
html.replace(MATH_RE, (s) =>
katex.renderToString(s)
);This page itself is proof
Every equation on the page you are reading is rendered by KaTeX live. No screenshots, no SVG, no MathJax. This right here. That is how light and natural it feels.
<TeX src={'\\Vert v \\Vert = ...'} />
// 5 lines, no library, just useMemo + dangerouslySetInnerHTMLFootguns : Pitfalls
KaTeX is simpler than MathJax, but four pitfalls show up over and over in issues / Stack Overflow. Know them once, save yourself the repeat.
Backslash escaping in JS strings
LaTeX's \frac must be written '\\frac' in a JS string (double backslash to produce one). This is the #1 KaTeX bug: users paste a LaTeX source into JS, the equation doesn't render, and the backslash got eaten.
Fix: template literals + backticks don't help (backslash still needs escaping). For real relief, keep LaTeX strings in external .tex / .md files and read them in.
\newcommand doesn't auto-load
The \newcommand{\RR}{\mathbb{R}} in your .tex preamble means nothing to KaTeX — there's no preamble concept. You must pass them via the macros option.
Fix: keep a project-level macros object, spread it into every render call, or wrap with a renderWithMacros(src) helper.
auto-render delimiter collisions
auto-render defaults to $...$ for inline math. But "$100, $200" in a price list parses as $1$00, $2$00.
Fix: disable the single $ delimiter, keep only $$...$$ and \(...\); or escape prices as \$100.
Import katex.min.css exactly once
import 'katex/dist/katex.min.css' belongs in your top-level entry. Importing it per component duplicates it in the bundle and flashes styles in dev.
For SSR / static generation: link katex.min.css straight from the HTML head; the client can skip the import entirely. The prediction pages on this site work that way.
Outlook : TheNext5Years
KaTeX in 2026 has entered "stable success" — feature work has slowed, but usage quietly climbs on the wave of LLMs emitting LaTeX. Four cards on what to expect over the next 3–5 years.
LLM outputs LaTeX → KaTeX renders — the quiet KaTeX renaissance
KaTeX's biggest 2026 customer is every AI chat UI: ChatGPT, Claude, Gemini, Perplexity. Their replies routinely contain $...$ for math. The renderer underneath is almost always KaTeX — fast, tiny bundle, graceful error fallback.
Users never notice: they only see "AI math looks great." But KaTeX's download counts and CDN hits have grown an order of magnitude over two years. It is now on the critical path of the AI era.
MathML Core (W3C 2023) — a threat?
MathML Core finalised in W3C 2023; Chromium 109+ ships native support. In theory browsers can render math directly, no KaTeX needed. In practice: cross-browser visual inconsistency remains huge — Firefox / Safari / Chrome's MathML output simply doesn't match. KaTeX's HTML+CSS path is pixel-identical everywhere — that moat is good for at least five more years.
SwiftLaTeX / texlive.js — different lane
Since 2020 WebAssembly TeX engines (SwiftLaTeX, tectonic-wasm) run full LaTeX in the browser: TikZ, BibTeX, PDF output, all of it. But the bundles are 20MB+, multi-second cold start — they live in a different use case from KaTeX: paper preview vs inline web math. The two don't compete.
Steady maintenance — not decline
KaTeX no longer ships monthly, no longer chases new features. But "successful projects look like this": tight scope, low bug count, no complaints. SQLite / curl / KaTeX all belong to this category. Steady state isn't death — it's "the work is done".