Cannot enable KaTeX with Hugo-Coder

  • Hello, everybody. I am a newbie to Hugo (just started using in yesterday). So apologies for silly questons in advance. I was trying to create a website in which I needed to render a few equations. I’ve been using the “hugo-coder” (https: // github. com / luizdepra/hugo-coder) theme. I followed a post ( https: // github. com / luizdepra/hugo-coder/blob/main/exampleSite/content/posts/math-typesetting.md) which came with the theme, but cannot render the equations with KaTeX. Here’s what I did -
  1. Copied the themes/hugo-coder/layouts/partials/posts/math.html to layouts/partials/.
    The contents of the math.html file:
{{- if or (.Params.math) (.Site.Params.math) (.Params.katex) (.Site.Params.katex) -}}
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css"
    integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
  {{/* The loading of KaTeX is deferred to speed up page rendering */}}
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js"
    integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js"
    integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"
    onload="renderMathInElement(document.body,
      {
        delimiters: [
          {left: '$$', right: '$$', display:true},
          {left: '$', right: '$', display:false},
          {left: '\\(', right: '\\)', display: false},
          {left: '\\[', right: '\\]', display: true}
        ]
      }
    );"></script>
{{- end -}}
  1. Copied themes/hugo-coder/layouts/_default/single.html to layouts/_default/.
    The single.html has:
{{ define "title" }}
  {{ .Title }} · {{ .Site.Title }}
{{ end }}
{{ define "content" }}
  {{ partial "page.html" . }}
  {{ partial "posts/math.html" . }}
{{ end }}
  1. Copied the snippet in the post (https: // github. com /luizdepra/hugo-coder/blob/main/exampleSite/content/posts/math-typesetting.md) to layouts/_default/single.html. The single.html now has:
{{ define "title" }}
  {{ .Title }} · {{ .Site.Title }}
{{ end }}
{{ define "content" }}
  {{ partial "page.html" . }}
  {{ if or .Params.math .Site.Params.math }}
    {{ partial "math.html" . }}
  {{ end }}
{{ end }}
  1. Now I set math: true in one page of the site, but it is still not working :face_with_thermometer:.
---
title: "Legendre Polynomials"
date: 2022-01-06T13:03:52+05:30
draft: false
math: true
---

## Rodrigues Formula:

$$ P_n(x) = \frac{d}{dx} \frac{1}{2^n n!} (x^2 - 1)^n $$

(https: // gitlab. com /ShirshenduSaha/sciputer-mock-up-site/-/blob/main/content/blog/Legendre-Polynomials.md)

Please help with how I can fix this issue.


My website and git repo, if needed.


It’s not working for you because you’re calling the partial at the wrong place. It should be at the top level inside body tag.

Since you’re calling the “math” partial inside the content block, it gets inlined inside a div which shouldn’t happen.

If you check the console, this is error.

You can refer how to properly load the CSS and JS by reading the official docs:

1 Like

Updated the math.html to have the contents:

<!DOCTYPE html>
<!-- KaTeX requires the use of the HTML5 doctype. Without it, KaTeX may not render properly -->
<html>
  <head>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css"
      integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs"
      crossorigin="anonymous"
    />

    <!-- The loading of KaTeX is deferred to speed up page rendering -->
    <script
      defer
      src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js"
      integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx"
      crossorigin="anonymous"
    ></script>

    <!-- To automatically render math in text elements, include the auto-render extension: -->
    <script
      defer
      src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js"
      integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR"
      crossorigin="anonymous"
      onload="renderMathInElement(document.body,
      {
        delimiters: [
          {left: '$$', right: '$$', display:true},
          {left: '$', right: '$', display:false},
          {left: '\\(', right: '\\)', display: false},
          {left: '\\[', right: '\\]', display: true}
        ]
      }
    );"
    ></script>
  </head>
</html>

Could you please suggest how the single.html should look like …
Thanks in advance.

From a quick look at the theme source, I don’t think you can specify it via single.html. You’ll have to override the baseof.html layout. Just copy it to your site repo and insert the KaTeX part there.

Moreover, you can ensure that it only runs on pages with the math param by using {{ if .Param.math }}.

Thanks for helping :slight_smile:

layouts/partials/math.html :

{{- if or (.Params.math) (.Site.Params.math) (.Params.katex) (.Site.Params.katex) -}}
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css"
    integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
  {{/* The loading of KaTeX is deferred to speed up page rendering */}}
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js"
    integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js"
    integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"
    onload="renderMathInElement(document.body,
      {
        delimiters: [
          {left: '$$', right: '$$', display:true},
          {left: '$', right: '$', display:false},
          {left: '\\(', right: '\\)', display: false},
          {left: '\\[', right: '\\]', display: true}
        ]
      }
    );"></script>
{{- end -}}

layouts/_default/baseof.html (the partial "math.html" . is added towards the last) :

<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Language" content="{{ .Site.Language.Lang }}">
    <meta name="color-scheme" content="light dark">

    {{ if .Site.Params.csp }}
      {{ partial "csp.html" . }}
    {{ end }}

    {{ with .Site.Params.author }}<meta name="author" content="{{ . }}">{{ end }}
    <meta name="description" content="{{ .Description | default (.Summary | default .Site.Params.description ) }}">
    <meta name="keywords" content="{{ (delimit .Keywords ",") | default .Site.Params.keywords }}">

    {{ template "_internal/twitter_cards.html" . }}
    {{ template "_internal/opengraph.html" . }}

    <title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>

    {{ if .Permalink }}
      <link rel="canonical" href="{{ .Permalink }}">
    {{ end }}

    <link rel="preload" href="/fonts/forkawesome-webfont.woff2?v=1.2.0" as="font" type="font/woff2" crossorigin>

    {{ if .Site.IsServer }}
      {{ $cssOpts := (dict "targetPath" "css/coder.css" "enableSourceMap" true ) }}
      {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts }}
      <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
    {{ else }}
      {{ $cssOpts := (dict "targetPath" "css/coder.css" ) }}
      {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts | minify | fingerprint }}
      <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
    {{ end }}

    {{ if .Site.Params.rtl }}
      {{ if .Site.IsServer }}
        {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" "enableSourceMap" true ) }}
        {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" ) }}
        {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}

    {{ if  or (eq .Site.Params.colorScheme "auto") (eq .Site.Params.colorScheme "dark") }}
      {{ if .Site.IsServer }}
        {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" "enableSourceMap" true ) }}
        {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" ) }}
        {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}

    {{ range .Site.Params.customCSS }}
      {{ if $.Site.IsServer }}
        {{ $styles := resources.Get . }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $styles := resources.Get . | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}

    {{ range .Site.Params.customSCSS }}
      {{/* We don't change the targetPath to because it's transparent to users */}}
      {{ if $.Site.IsServer }}
        {{ $cssOpts := (dict "enableSourceMap" true ) }}
        {{ $styles := resources.Get . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $styles := resources.Get . | toCSS | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}

    <link rel="icon" type="image/png" href="{{ .Site.Params.favicon_32 | default "/images/favicon-32x32.png" | relURL }}" sizes="32x32">
    <link rel="icon" type="image/png" href="{{ .Site.Params.favicon_16 | default "/images/favicon-16x16.png" | relURL }}" sizes="16x16">

    <link rel="apple-touch-icon" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
    <link rel="apple-touch-icon" sizes="180x180" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">

    {{ range .AlternativeOutputFormats -}}
      {{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink $.Site.Title | safeHTML }}
    {{ end -}}

    {{ hugo.Generator }}
  </head>

  {{ $csClass := "colorscheme-light" }}
  {{ if eq .Site.Params.colorScheme "dark" }}
    {{ $csClass = "colorscheme-dark" }}
  {{ else if eq .Site.Params.colorScheme "auto" }}
    {{ $csClass = "colorscheme-auto" }}
  {{ end }}
  <body class="preload-transitions {{ $csClass }}{{ if .Site.Params.rtl }} rtl{{ end }}">
    {{ partial "float" . }}
    <main class="wrapper">
      {{ partial "header.html" . }}

      <div class="content">
        {{ block "content" . }}{{ end }}
      </div>

      {{ partial "footer.html" . }}
    </main>

    {{ if .Site.IsServer }}
      {{ $script := resources.Get "js/coder.js" }}
      <script src="{{ $script.RelPermalink }}"></script>
    {{ else }}
      {{ $script := resources.Get "js/coder.js" | minify | fingerprint }}
      <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
    {{ end }}

    {{ range .Site.Params.customJS }}
      {{ if $.Site.IsServer }}
        {{ $script := resources.Get . }}
        <script src="{{ $script.RelPermalink }}"></script>
      {{ else }}
        {{ $script := resources.Get . | minify | fingerprint }}
        <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
      {{ end }}
    {{ end }}

    {{ template "_internal/google_analytics.html" . }}

    {{ if and .Site.Params.fathomAnalytics .Site.Params.fathomAnalytics.siteID }}
      {{- partial "analytics/fathom" . -}}
    {{ end }}

    {{ if and .Site.Params.plausibleAnalytics .Site.Params.plausibleAnalytics.domain }}
      {{- partial "analytics/plausible" . -}}
    {{ end }}

    {{ if and .Site.Params.goatCounter .Site.Params.goatCounter.code }}
      {{- partial "analytics/goatcounter" . -}}
    {{ end }}

    {{ if and .Site.Params.cloudflare .Site.Params.cloudflare.token }}
      {{- partial "analytics/cloudflare" . -}}
    {{ end }}

    {{ if and .Site.Params.matomo .Site.Params.matomo.serverURL }}
      {{- partial "analytics/matomo" . -}}
    {{ end }}

    {{ if and .Site.Params.googleTagManager .Site.Params.googleTagManager.id }}
      {{- partial "analytics/googletagmanager" . -}}
    {{ end }}

    {{ if or .Params.math .Site.Params.math }}
      {{ partial "math.html" . }}
    {{ end }}

  </body>

</html>

Still not working …

What you’ve done seems fine. Give me the errors from the console or push the changes to your website so I can have a look.

Already pushed the changes to the site.

The partial is not being included in the HTML source. Double-check your partial and your content files and try to debug why the partial isn’t loading.
It should start working once you have the script and link tags for KaTeX near the closing body tag. You can verify this by inspecting the page source in your browser with the local server on.

The web dev tools shows:

And the console errors:


Not sure, but the error seems related to the floowing line in config.toml:

scriptsrc = ["'self'", "'unsafe-inline'", "https://www.google-analytics.com"]

If I am right, how can I fix that?

Adding “https://cdn.jsdelivr.net” in the site’s config.toml solved the issue.
Kind of a hacky thing, but removed the

{{ if .Site.Params.csp }}
  {{ partial "csp.html" . }}
{{ end }}

section in the head tag of layouts/_default/baseof.html and it worked! Can anyone explin how?

[By the way, I was doing trial and error and in the process, removed the scriptsrc line in config.toml and then running on localhost gave the error:

render of "page" failed: execute of template failed: template: _default/single.html:11:9: executing "_default/single.html" at <partial "csp.html" .>: error calling partial: "/home/shirshendu/Documents/Website/sciputer-mock-up-site/layouts/partials/csp.html:1:565": execute of template failed: template: partials/csp.html:1:565: executing "partials/csp.html" at <delimit .Site.Params.csp.scriptsrc " ">: error calling delimit: can't iterate over <nil>
render of "section" failed: execute of template failed: template: _default/list.html:11:9: executing "_default/list.html" at <partial "csp.html" .>: error calling partial: "/home/shirshendu/Documents/Website/sciputer-mock-up-site/layouts/partials/csp.html:1:565": execute of template failed: template: partials/csp.html:1:565: executing "partials/csp.html" at <delimit .Site.Params.csp.scriptsrc " ">: error calling delimit: can't iterate over <nil>
render of "page" failed: execute of template failed: template: _default/single.html:11:9: executing "_default/single.html" at <partial "csp.html" .>: error calling partial: "/home/shirshendu/Documents/Website/sciputer-mock-up-site/layouts/partials/csp.html:1:565": execute of template failed: template: partials/csp.html:1:565: executing "partials/csp.html" at <delimit .Site.Params.csp.scriptsrc " ">: error calling delimit: can't iterate over <nil>
render of "home" failed: execute of template failed: template: index.html:11:9: executing "index.html" at <partial "csp.html" .>: error calling partial: "/home/shirshendu/Documents/Website/sciputer-mock-up-site/layouts/partials/csp.html:1:565": execute of template failed: template: partials/csp.html:1:565: executing "partials/csp.html" at <delimit .Site.Params.csp.scriptsrc " ">: error calling delimit: can't iterate over <nil>
failed to render pages: render of "page" failed: execute of template failed: template: _default/single.html:11:9: executing "_default/single.html" at <partial "csp.html" .>: error calling partial: "/home/shirshendu/Documents/Website/sciputer-mock-up-site/layouts/partials/csp.html:1:565": execute of template failed: template: partials/csp.html:1:565: executing "partials/csp.html" at <delimit .Site.Params.csp.scriptsrc " ">: error calling delimit: can't iterate over <nil>
hugo v0.91.2+extended linux/amd64 BuildDate=unknown

Reload Page

Then I removed the csp section in baseof.html]
And @UtkarshVerma,

how does one know what template is being sourced? (I am new to the website related things, so any help is much apprecited). Thanks.

That is a CSP error and to fix it you need to include the hash of the JS scripts for KaTex.

The headers in the project config are about the local Hugo server (see the doc)

You need to fix the access control headers in your build environment.

If you are deploying to Netlify then the place to include the hash is in netlify.toml.

To calculate the hash use Chrome Dev tools and you will see it displayed next to the script that is missing it.

We cannot provide further assistance for CSP errors in this forum.

Search other places like for example the MDN doc etc.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.