Table of Contents

How to render math in Astro - A detailed guide

Starting points#

KaTeX\KaTeX is what we are going to use to render the math from the markdown documents. On a very high level it parses everything within $...$ or $$...$$ in your documents and applies css styles to it. The docs are pretty detailed although it can get somewhat vague at times; check them out here.

To wire this into Astro you need two plugins - remark-math (parses the $...$ and $$...$$ syntax into math nodes) and rehype-katex (turns those nodes into the actual KaTeX\KaTeX HTML). Install both along with katex itself:

Shell
npm install remark-math rehype-katex katex

Now, there are two ways to plug these into astro.config.mjs, depending on how much control you want over the markdown pipeline:

  • If you are on the default markdown setup, you can just pass them as markdown.remarkPlugins and markdown.rehypePlugins.
  • If you already have a custom unified() processor (which is the case on this site, since Shiki config and other plugins live there too), plug them into that instead:
astro.config.mjsJavaScript
import { defineConfig } from "astro/config";
import { unified } from "@astrojs/markdown-remark";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
export default defineConfig({
markdown: {
processor: unified({
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
}),
},
});

Order matters here - remark-math runs on the markdown AST before it turns into HTML, rehype-katex runs after. Get this backwards and nothing renders, it just silently leaves your $...$ as plain text.

Customising KaTeX\KaTeX#

KaTeX\KaTeX does a somewhat poor job of explaining how to customise the styles in its own docs. It outlines here how the fonts can be customised, and you should - KaTeX\KaTeX fonts differ considerably from the LaTeX\LaTeX default, which is Computer Modern Roman.

Here is the procedure we actually use on this site:

  • Motivation: We want to overwrite the default styles KaTeX\KaTeX applies, as defined in katex.min.css.
  • Self-host katex.min.css instead of pulling it from a CDN - copy it from node_modules/katex/dist/katex.min.css into public/styles/. Do the same for the font files in node_modules/katex/dist/fonts/ if you plan to keep any of KaTeX’s own fonts.
  • Load another local stylesheet after katex.min.css, which redefines only the classes you want to change.
BaseLayout.astroHTML
<link rel="stylesheet" href="/styles/katex.min.css" />
<link rel="stylesheet" href="/styles/katex-custom.css" />

We take this one step further on this site and swap out KaTeX\KaTeX‘s own math fonts entirely for Computer Modern, so that math matches the rest of the body text. That means declaring @font-face rules for each font family and then remapping every KaTeX\KaTeX class (.mathrm, .mathit, .mathbf, .mathcal, .mathfrak, and so on) to point at them:

katex-custom.cssCSS
@font-face {
font-family: "ComputerModernRoman";
font-style: normal;
font-weight: normal;
src: url("/fonts/cm/cm-serif.ttf") format("truetype");
}
.katex {
font-family: "ComputerModernRoman";
}
.katex .mathrm {
font-family: "ComputerModernRoman";
font-style: normal;
}
  • Where does this local stylesheet go? Referring the Astro docs, local stylesheets live in public/styles/. Same idea as how fonts live in public/fonts/.
  • Just open the actual katex.min.css file to see the class names, then override whichever ones you care about. You can override colors, weights, whatever - not just fonts.

Extras#

If you want the exact LaTeX\LaTeX fonts, download Computer Modern from here, self-host the .ttf files under public/fonts/, and wire them up in katex-custom.css as shown above. Two things worth remembering:

  • Self-hosting means no CDN dependency and no request to a third party at page load - worth doing for a static site anyway.
  • KaTeX\KaTeX’s own fonts still render fine if you skip this step - Computer Modern is a purely aesthetic choice to match a LaTeX\LaTeX-like look.