Aller au contenu

MkDocs Installation

This page explains how to install TikZJax on an MkDocs site, particularly one using Material for MkDocs.

The recommended integration uses:

  1. a local TikZJax configuration file;
  2. the TikZJax font stylesheet;
  3. the TikZJax JavaScript bundle;
  4. an optional Superfences configuration for fenced tikzjax blocks.

TikZJax renders diagrams entirely in the browser. It does not require a server-side LaTeX installation.


Installation overview

Add the following files to the MkDocs project:

mkdocs.yml
docs/
    assets/
        javascripts/
            tikzjax.config.js
overrides/
    main.html

The exact documentation directory may differ when docs_dir is customized.

The recommended loading order is:

1. tikzjax.config.js
2. fonts.min.css
3. tikzjax.min.js

The configuration must be loaded before the TikZJax bundle.


overrides/main.html

Create or update:

overrides/main.html

with:

{% extends "base.html" %}

{% block libs %}
    {{ super() }}

    <script src="{{ 'assets/javascripts/tikzjax.config.js' | url }}"></script>

    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/fonts.min.css"
    >

    <script
      src="https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/tikzjax.min.js"
      defer
    ></script>
{% endblock %}

This is normally the only Material template override required by TikZJax.

Preserve the parent template

Keep:

```html
{{ super() }}
```

inside the `libs` block.

It preserves the scripts and resources loaded by Material for MkDocs.

Enable the Material override directory

Configure the custom template directory in mkdocs.yml:

theme:
  name: material
  custom_dir: overrides

A minimal configuration is:

site_name: My Documentation

theme:
  name: material
  custom_dir: overrides

Create:

docs/assets/javascripts/tikzjax.config.js

with:

window.TikzJaxOptions = {
    renderTimeout: 30000,
    maxRetries: 1,
    restartWorkerOnFail: true,

    workerPool: {
        enabled: true,
        maxWorkers: 3,
        reserveCpuCores: 1,
        useDeviceMemory: true,
        initializationRetries: 1
    },

    tex: {
        texPackages: {},
        tikzLibraries: []
    }
};

This configuration provides:

  • bounded parallel rendering;
  • adaptive worker-pool sizing;
  • one retry after a transient failure;
  • replacement of failed workers;
  • a finite render timeout;
  • a small global TeX preamble.

Specialized packages and TikZ libraries should normally be declared locally on the diagrams that require them.

See Configuration.


Minimal HTML diagram

TikZJax directly recognizes:

<script type="text/tikz">
\begin{tikzpicture}
    \draw[very thick]
        (0,0) circle (1);
\end{tikzpicture}
</script>

Rendered result:

This syntax requires no special Markdown extension.

It is also the preferred syntax when a diagram needs local packages, libraries, macros, timeouts, or debugging attributes.


Fenced tikzjax blocks

Configure Superfences

To use fenced Markdown blocks, configure pymdownx.superfences in mkdocs.yml:

markdown_extensions:
  - pymdownx.superfences:
      custom_fences:
        - name: tikzjax
          class: language-tikzjax
          format: !!python/name:pymdownx.superfences.fence_code_format

You can then write:

```tikzjax
\begin{tikzpicture}
    \draw[->]
        (0,0) -- (3,0)
        node[right] {$x$};

    \draw[->]
        (0,0) -- (0,2)
        node[above] {$y$};

    \draw[very thick]
        (0,0) -- (2.5,1.5);
\end{tikzpicture}
```

Rendered result:

\begin{tikzpicture}
    \draw[->]
        (0,0) -- (3,0)
        node[right] {$x$};

    \draw[->]
        (0,0) -- (0,2)
        node[above] {$y$};

    \draw[very thick]
        (0,0) -- (2.5,1.5);
\end{tikzpicture}

HTML blocks versus fenced blocks

Capability HTML <script> block Fenced tikzjax block
Standard TikZ source Yes Yes
Local TeX packages Yes No
Local TikZ libraries Yes No
Local custom preamble Yes No
Local timeout Yes No
Cache bypass Yes No
Debug console Yes No
Loader dimensions Yes No

Fenced blocks contain only the TeX source.

They cannot carry HTML data-* attributes.

Use a fenced block when the source depends only on globally available packages and libraries.

Use <script type="text/tikz"> when the diagram needs specialized local configuration.


Package dependencies in fenced blocks

Suppose a fenced block uses tkz-tab:

```tikzjax
\begin{tikzpicture}
    \tkzTabInit
        {$x$/1,$f(x)$/2}
        {$-\infty$,$0$,$+\infty$}

    \tkzTabVar{
        -/$-\infty$,
        +/$2$,
        -/$-\infty$
    }
\end{tikzpicture}
```

Because the fenced block cannot declare a local package, tkz-tab must be loaded globally:

window.TikzJaxOptions = {
    tex: {
        texPackages: {
            "tkz-tab": ""
        }
    }
};

Alternatively, use an HTML block and load the package locally:

<script
  type="text/tikz"
  data-tex-packages="tkz-tab"
>
\begin{tikzpicture}
    \tkzTabInit
        {$x$/1,$f(x)$/2}
        {$-\infty$,$0$,$+\infty$}

    \tkzTabVar{
        -/$-\infty$,
        +/$2$,
        -/$-\infty$
    }
\end{tikzpicture}
</script>

Local loading is preferable when only a small number of diagrams require the package.


Complete mkdocs.yml example

The following example enables common Material features and fenced TikZJax blocks:

site_name: My Documentation
site_url: https://example.com/

theme:
  name: material
  custom_dir: overrides
  language: en

  features:
    - navigation.sections
    - navigation.top
    - content.code.copy

  palette:
    - media: "(prefers-color-scheme: light)"
      scheme: default
      primary: blue
      accent: blue

      toggle:
        icon: material/weather-night
        name: Switch to dark mode

    - media: "(prefers-color-scheme: dark)"
      scheme: slate
      primary: pink
      accent: pink

      toggle:
        icon: material/weather-sunny
        name: Switch to light mode

nav:
  - Home: index.md

markdown_extensions:
  - admonition
  - attr_list
  - md_in_html
  - pymdownx.details

  - pymdownx.superfences:
      custom_fences:
        - name: tikzjax
          class: language-tikzjax
          format: !!python/name:pymdownx.superfences.fence_code_format

  - pymdownx.tabbed:
      alternate_style: true

TikZJax does not require every extension in this example.

Only the custom Superfences configuration is required for fenced tikzjax syntax.

HTML <script type="text/tikz"> blocks work without Superfences.


Local diagram configuration

Local TeX package

<script
  type="text/tikz"
  data-tex-packages="physics"
>
\begin{tikzpicture}
    \node[
        draw,
        rounded corners,
        inner sep=7pt
    ] {
        $\vb{F}=m\vb{a}$
    };
\end{tikzpicture}
</script>

Several local packages

Use compact JSON:

<script
  type="text/tikz"
  data-tex-packages='{"physics":"","xcolor":"dvipsnames"}'
>
\begin{tikzpicture}
    \node[text=NavyBlue] {
        $\vb{F}=m\vb{a}$
    };
\end{tikzpicture}
</script>

The package names are mapped to their option strings.

An empty string means no package options.


Local TikZ libraries

<script
  type="text/tikz"
  data-tikz-libraries="arrows.meta,positioning"
>
\begin{tikzpicture}
    \node (A) {
        Start
    };

    \node[
        right=2cm of A
    ] (B) {
        End
    };

    \draw[-{Stealth}]
        (A) -- (B);
\end{tikzpicture}
</script>

TikZ libraries must not be declared as TeX packages.

For example, braids is loaded with:

data-tikz-libraries="braids"

Local preamble

<script
  type="text/tikz"
  data-add-to-preamble="\newcommand{\localR}{\mathbb{R}}"
>
\begin{tikzpicture}
    \node {
        $f:\localR\to\localR$
    };
\end{tikzpicture}
</script>

A local data-add-to-preamble value replaces the configured global custom preamble for that diagram.

Include every custom definition required by the local source.


Local timeout

<script
  type="text/tikz"
  data-render-timeout="45000"
>
\begin{tikzpicture}
    % Complex diagram
\end{tikzpicture}
</script>

The timeout applies only to this diagram.


Loader dimensions

<script
  type="text/tikz"
  data-width="620"
  data-height="300"
>
\begin{tikzpicture}
    % Large diagram
\end{tikzpicture}
</script>

These values reserve space while the diagram is compiling.

They do not resize the generated SVG.


Local debugging

<script
  type="text/tikz"
  data-disable-cache="true"
  data-show-console="true"
  data-debug-timings="true"
  data-render-timeout="45000"
>
\begin{tikzpicture}
    \draw (0,0) circle (1);
\end{tikzpicture}
</script>

This configuration:

  • bypasses the persistent SVG cache;
  • shows TeX console output;
  • shows worker timings;
  • increases the local timeout.

Remove these debugging attributes before publishing the page.


Diagrams inside Material components

Admonitions

TikZJax scans nested DOM content, so diagrams can be used inside admonitions.

!!! success "Rendered diagram"

    ```tikzjax
    \begin{tikzpicture}
        \draw (0,0) circle (1);
    \end{tikzpicture}
    ```

Indentation must be valid Markdown.


Collapsible admonitions

??? example "Open the diagram"

    ```tikzjax
    \begin{tikzpicture}
        \draw (0,0) rectangle (3,2);
    \end{tikzpicture}
    ```

TikZJax observes dynamically revealed and inserted content.


Content tabs

=== "Question"

    Determine the length of the segment.

=== "Diagram"

    ```tikzjax
    \begin{tikzpicture}
        \draw[very thick]
            (0,0) -- (4,0);

        \fill
            (0,0) circle (2pt)
            (4,0) circle (2pt);
    \end{tikzpicture}
    ```

When tab content becomes visible, TikZJax can rescan and reprioritize its diagrams.

The diagram joins the same global render queue and worker pool as the rest of the page.


Client-side navigation

Material for MkDocs can replace page content without performing a complete browser reload.

TikZJax uses centralized DOM observation to detect newly inserted source blocks.

This supports:

  • client-side page navigation;
  • content tabs;
  • dynamically inserted Markdown;
  • delayed components;
  • collapsible sections.

TikZJax should be loaded once in the site template.

Do not add the TikZJax bundle separately to individual Markdown pages.

Loading it several times can create:

  • duplicate DOM observers;
  • duplicate theme observers;
  • conflicting worker pools;
  • repeated processing;
  • inconsistent configuration.

Completion order

With several rendering workers, diagrams may finish in a different order from their source order.

source order:
A, B, C

completion order:
B, C, A

Each SVG is still inserted in the correct document position.

Use the completion event when JavaScript must react to rendered output:

document.addEventListener(
    "tikzjax-load-finished",
    function (event) {
        const svg = event.target;

        console.log(
            "TikZJax diagram ready:",
            svg
        );
    }
);

See Parallel Rendering and the Worker Pool.


Theme integration

Material stores the active color scheme in:

data-md-color-scheme

Common values are:

default
slate

TikZJax can normally detect Material themes automatically.

An explicit configuration can be used when required:

window.TikzJaxOptions = {
    theme: {
        selector: "body",
        attribute: "data-md-color-scheme",
        darkValue: "slate",
        lightValue: "default",
        fallbackTheme: "light"
    }
};

TikZJax can adapt common default black, white, stroke, fill, and text colors after SVG generation.

Theme changes do not require recompiling the TeX source.

See Themes.


MathJax integration

MathJax is optional.

TikZJax renders TikZ-based diagrams.

MathJax renders mathematical expressions in the surrounding documentation.

They use different configuration objects:

window.TikzJaxOptions = {};
window.MathJax = {};

A typical MathJax setup might use:

markdown_extensions:
  - pymdownx.arithmatex:
      generic: true
      smart_dollar: false

extra_javascript:
  - assets/javascripts/mathjax.js
  - https://cdn.jsdelivr.net/npm/mathjax@4.1.0/tex-mml-chtml.js

TikZJax source elements are normally protected from MathJax because:

  • HTML TikZ source is placed inside a script element;
  • fenced source is initially placed inside pre and code;
  • generated output is wrapped in a mathjax_ignore container.

Load TikZJax once through the Material template and configure MathJax separately.


Arithmatex compatibility

Some MkDocs configurations transform inline mathematics before TikZJax reads the page.

TikZJax includes source cleanup for common Arithmatex wrappers associated with script-based TikZ sources.

When a source still changes unexpectedly:

  1. inspect the final HTML;
  2. compare the source text before and after Markdown processing;
  3. test the same source in a plain <script type="text/tikz"> block;
  4. avoid applying Markdown transformations inside the script source.

CDN runtime assets

TikZJax requires files such as:

tikzjax.min.js
run-tex.js
fonts.min.css
tex.wasm.gz
core.dump.gz
tex_files/
assets/broken-image.svg

When loaded from:

https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/tikzjax.min.js

TikZJax normally resolves the other assets from:

https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/

No explicit assetBaseUrl is normally required.


unpkg

Replace the jsDelivr URLs with:

<link
  rel="stylesheet"
  href="https://unpkg.com/@rod2ik/tikzjax@1.5.0/dist/fonts.min.css"
>

<script
  src="https://unpkg.com/@rod2ik/tikzjax@1.5.0/dist/tikzjax.min.js"
  defer
></script>

Keep the configuration file before the TikZJax script.


Same-origin MkDocs installation

TikZJax can be served from the MkDocs site itself.

Place the runtime files under the documentation directory:

docs/
    vendor/
        tikzjax/
            tikzjax.min.js
            run-tex.js
            fonts.min.css
            tex.wasm.gz
            core.dump.gz
            tex_files/
            assets/
                broken-image.svg

MkDocs copies these files into the generated site.


Root-hosted deployment

For a site hosted at the origin root:

window.TikzJaxOptions = {
    assetBaseUrl: "/vendor/tikzjax",
    workerMode: "direct",

    renderTimeout: 30000,
    maxRetries: 1,
    restartWorkerOnFail: true,

    workerPool: {
        enabled: true,
        maxWorkers: 3,
        reserveCpuCores: 1,
        useDeviceMemory: true,
        initializationRetries: 1
    }
};

Load the assets in overrides/main.html:

{% extends "base.html" %}

{% block libs %}
    {{ super() }}

    <script src="{{ 'assets/javascripts/tikzjax.config.js' | url }}"></script>

    <link
      rel="stylesheet"
      href="{{ 'vendor/tikzjax/fonts.min.css' | url }}"
    >

    <script
      src="{{ 'vendor/tikzjax/tikzjax.min.js' | url }}"
      defer
    ></script>
{% endblock %}

Sites deployed under a subpath

A root-relative value such as:

assetBaseUrl: "/vendor/tikzjax"

assumes that the site is hosted at the origin root.

For a site deployed under a subpath, define the asset base in the template so MkDocs resolves the correct URL:

{% extends "base.html" %}

{% block libs %}
    {{ super() }}

    <script>
    window.TikzJaxOptions = {
        assetBaseUrl:
            "{{ 'vendor/tikzjax' | url }}",

        workerMode: "direct",

        renderTimeout: 30000,
        maxRetries: 1,
        restartWorkerOnFail: true,

        workerPool: {
            enabled: true,
            maxWorkers: 3,
            reserveCpuCores: 1,
            useDeviceMemory: true,
            initializationRetries: 1
        }
    };
    </script>

    <link
      rel="stylesheet"
      href="{{ 'vendor/tikzjax/fonts.min.css' | url }}"
    >

    <script
      src="{{ 'vendor/tikzjax/tikzjax.min.js' | url }}"
      defer
    ></script>
{% endblock %}

This avoids hard-coding the deployment prefix.

All runtime files must come from the same TikZJax release.


Worker modes

TikZJax supports:

Mode Purpose
"auto" Direct same-origin workers and Blob cross-origin workers
"blob" Force Blob-worker startup
"direct" Force direct worker startup

Recommended values:

Deployment Mode
jsDelivr or unpkg "auto"
CDN with Blob workers explicitly allowed "auto" or "blob"
Same-origin MkDocs assets "direct"
Strict CSP without blob: "direct"

Default CDN configuration:

window.TikzJaxOptions = {
    workerMode: "auto"
};

Same-origin configuration:

window.TikzJaxOptions = {
    assetBaseUrl: "/vendor/tikzjax",
    workerMode: "direct"
};

Root workerMode and workerUrl take precedence over nested worker.mode and worker.url.


Content Security Policy

CDN with Blob workers

A typical policy includes:

default-src 'self';
script-src 'self' https://cdn.jsdelivr.net https://unpkg.com 'wasm-unsafe-eval';
style-src 'self' https://cdn.jsdelivr.net https://unpkg.com 'unsafe-inline';
worker-src 'self' blob:;
connect-src 'self' https://cdn.jsdelivr.net https://unpkg.com;
img-src 'self' https://cdn.jsdelivr.net https://unpkg.com data: blob:;
font-src 'self' https://cdn.jsdelivr.net https://unpkg.com;
object-src 'none';

Same-origin direct workers

default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
style-src 'self' 'unsafe-inline';
worker-src 'self';
connect-src 'self';
img-src 'self' data:;
font-src 'self';
object-src 'none';

Adapt these examples to the complete site policy.


Production and debugging assets

Use in production:

fonts.min.css
tikzjax.min.js

Use while debugging:

fonts.css
tikzjax.js

Example debug loading:

{% extends "base.html" %}

{% block libs %}
    {{ super() }}

    <script src="{{ 'assets/javascripts/tikzjax.config.js' | url }}"></script>

    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/fonts.css"
    >

    <script
      src="https://cdn.jsdelivr.net/npm/@rod2ik/tikzjax@1.5.0/dist/tikzjax.js"
      defer
    ></script>
{% endblock %}

Restore the minified files before publishing.


Verify the installation

Build the documentation

mkdocs serve

Open the development site and verify the basic diagram.


Check the Network panel

These resources should load successfully:

tikzjax.min.js
fonts.min.css
run-tex.js
tex.wasm.gz
core.dump.gz

Package-heavy diagrams may request additional compressed files under:

tex_files/

Check the Console

There should be no:

  • configuration syntax error;
  • worker initialization failure;
  • WebAssembly error;
  • CSP violation;
  • CORS error;
  • missing runtime file;
  • TeX compilation error.

Test one local package

<script
  type="text/tikz"
  data-tex-packages="physics"
  data-disable-cache="true"
  data-show-console="true"
>
\begin{tikzpicture}
    \node {$\vb{F}=m\vb{a}$};
\end{tikzpicture}
</script>

If the basic circle works but this example fails, inspect requests under tex_files/.


Common MkDocs problems

Configuration file returns 404

Check that the file exists under the configured docs_dir.

Default location:

docs/assets/javascripts/tikzjax.config.js

Template path:

{{ 'assets/javascripts/tikzjax.config.js' | url }}

Fenced blocks display as source code

Check the pymdownx.superfences custom fence configuration.

Inspect the generated <pre> element and verify that it contains:

language-tikzjax

HTML source is removed

Some Markdown or sanitization configurations may remove <script> elements.

Check:

  • whether raw HTML is enabled;
  • whether a hosting platform sanitizes generated HTML;
  • whether an external Markdown processor removes script elements;
  • the final generated HTML.

When script elements are forbidden, use fenced blocks and load their dependencies globally.


Diagrams inside tabs are delayed

A hidden diagram may be assigned a lower viewport priority until the tab becomes visible.

Activating the tab triggers observation and reprioritization.

A job that already started is not normally interrupted merely because another tab becomes visible.


A diagram renders twice

Check that:

  • TikZJax is loaded only once;
  • overrides/main.html does not include the bundle in several blocks;
  • extra_javascript does not also contain TikZJax;
  • another template override does not inject the same script;
  • client-side navigation does not recreate the runtime manually.

A package works in HTML but not in a fenced block

The HTML source probably declares the package locally.

The fenced block cannot carry that declaration.

Load the dependency globally or keep the diagram as an HTML block.


A stale diagram remains visible

Force a fresh render:

data-disable-cache="true"

or clear IndexedDB:

indexedDB.deleteDatabase("TikzJax");
location.reload();

Related documentation