Adding LaTeX to your Jekyll Site

As it turns out, adding support to render LaTeX in a Jekyll blog isn’t all that hard, because other people have done most of the heavy lifting. There are two main ways to do this:

  • Client-side rendering: After the page loads, a JS script is run to transform LaTeXy parts of the page to lovely, styled HTML.
  • Build-time rendering: After Markdown files are compiled to HTML, a Jekyll plugin further transforms those LaTeXy parts to HTML as well. Here’s how you do either using KaTeX\KaTeX.

Client-Side KaTeX\KaTeX

Inside of your HTML <head> tag, usually in _layouts/default.html for Jekyll blogs, add the following to conditionally load stylesheets and scripts.

{% if page.katex %}

<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css"/>

<!-- JavaScript -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@latest/dist/contrib/auto-render.min.js"
  onload="renderMathInElement(document.body,{
    delimiters: [
      { left: '$$',  right: '$$',  display: true  },
      { left: '$',   right: '$',   display: false },
      { left: '\\[', right: '\\]', display: true  },
      { left: '\\(', right: '\\)', display: false }
  ]});">
</script>

{% endif %}

This uses jsDelivr as the CDN to deliver the styles and scripts; replace latest in the URLs if you want to stick to a specific version. It uses KaTeX’s auto-render extension to render everything within the specified delimiters. display: true is equivalent to a displaymath environment, while display: false is equivalent to an inline math environment. Their documentation has a few more options you can set, like which tags and classes to ignore during processing.

To use LaTeX in a post, add katex: true to the front matter, and write your LaTeX within the specified delimiters. For instance, the body of the following:

---
layout: post
title: "Your Post Title"
katex: true
---

This is an example of inline \\(\LaTeX\\). The following is Stokes' theorem in a
`displaymath` environment: \$$\int_{\partial \Omega} \omega = \int_{\Omega} d\omega\$$

is displayed as below:

This is an example of inline LaTeX\LaTeX. The following is Stokes’ theorem in a displaymath environment:
Ωω=Ωdω\displaystyle \int_{\partial \Omega} \omega = \int_{\Omega} d\omega

Note the extra backslashes to escape \ and \$ from being processed by kramdown. Sometimes you will need to escape underscores as well to prevent kramdown from rendering text as italics instead of subscripts: the double subscript ij_{i_j} is written as \$\_{i\_{j}}\$.

Build-Time KaTeX\KaTeX

Your LaTeX can be rendered during Jekyll’s build instead of on the client side by using the jekyll-katex plugin. Note that this will not work with GitHub Pages because they only allow supported plugins. The plugin repository has a detailed README, but to setup in short:

  1. Add to _config.yml.
    plugins:
    - jekyll-katex
    
  2. Add to Gemfile.
    group :jekyll_plugins do
      gem "github-pages"
      gem "jekyll-katex"
    end
    
  3. Again, add stylesheet to <head> (conditionally, if you like).
    {% if page.katex %}
    < link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css" />
    {% endif %}
    

You should probably replace latest with the version that the plugin comes with. It will only render LaTeX within specific Liquid tags. The example above can be written as:

This is an example of inline {% katex %}\LaTeX{% endkatex %}.
The following is Stokes' theorem in a `displaymath` environment:
{% katex display %}\int_{\partial \Omega} \omega = \int_{\Omega} d\omega{% endkatex %}

This is an example of inline LaTeX\LaTeX. The following is Stokes’ theorem in a displaymath environment:
Ωω=Ωdω\displaystyle \int_{\partial \Omega} \omega = \int_{\Omega} d\omega

Or using the mixed math environment:

{% katexmm %}
This is an example of inline $\LaTeX$. The following is Stokes' theorem in a
`displaymath` environment: $$\int_{\partial \Omega} \omega = \int_{\Omega} d\omega$$
{% endkatexmm %}

There is no need to escape any special characters, aside from \$ to actually represent a dollar sign. However, there doesn’t seem to be a way to customize the delimiters used in katexmm. The katex and katexmm Liquid tags can be ignored as usual, by wrapping content in {​% raw %}{​% endraw %} tags. Note also that they do not render when added to the front matter, such as in the title.

GitHub Pages \rightarrow GitLab Pages

Build-time rendering doesn’t work for GitHub Pages since they have a fixed set of Jekyll plugins. On the other hand, it will work for GitLab Pages, since the site generation is part of a CI pipeline. To port to GitLab, add the following to .gitlab-ci.yml.

image: ruby:2.7

pages:
  script:
    - apt-get update && apt-get -y install nodejs
    - gem install bundler
    - bundle install
    - bundle exec jekyll build -d public
  artifacts:
    paths:
      - public

If you use Ruby 3 instead, you will need to add webrick to your Gemfile (see issue #8523 for the Jekyll repo).

group :jekyll_plugins do
  gem "webrick"
  gem "github-pages"
  gem "jekyll-katex"
end

References