Skip to content

MathJax 4 Support#3811

Merged
hakimel merged 6 commits intohakimel:masterfrom
Khlick:feature/mathjax4-plugin
Jan 24, 2026
Merged

MathJax 4 Support#3811
hakimel merged 6 commits intohakimel:masterfrom
Khlick:feature/mathjax4-plugin

Conversation

@Khlick
Copy link
Copy Markdown
Contributor

@Khlick Khlick commented Aug 8, 2025

Summary

Adds a new MathJax4 plugin that supports MathJax 4.0.0 with proper async startup handling.

Changes

  • New plugin: plugin/math/mathjax4.js with MathJax 4.0.0 support
  • Updated plugin wrapper: Added MathJax4 to plugin/math/plugin.js exports
  • Example updated: examples/math.html now demonstrates MathJax4 configuration
  • Tests added: Comprehensive test suite in test/test-mathjax4.html (all passing)
  • Built files: Updated math.js and math.esm.js with new plugin
  • Version bump: Package version updated to 5.2.2

Key Features

  • MathJax 4.0.0 Support: Uses latest MathJax CDN with async startup
  • Macros Support: Compatible macro configuration similar to MathJax3
  • Async Startup: Proper handling of MathJax 4's async initialization
  • Slide Change Support: Re-typesets math when slides become visible
  • Backward Compatible: Same API as other math plugins

Configuration Example

mathjax4: {
    tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']],
        displayMath: [['$$', '$$'], ['\\[', '\\]']],
        macros: {
            R: '\\mathbb{R}',
            set: ['\\left\\{#1 \\; ; \\; #2\\right\\}', 2]
        }
    },
    options: {
        skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    },
    output: {
        font: 'mathjax-stix2',
        displayOverflow: 'linebreak',
        linebreaks: {
            inline: true,
            width: '100%',
            lineleading: .2
        }
    }
}

Testing

  • QUnit Tests: All 5 tests passing in test/test-mathjax4.html
    • Plugin availability and structure ✅
    • Plugin initialization ✅
    • MathJax 4.0.0 loading and math processing ✅
    • Custom macros functionality ✅
  • Manual Verification: Tested examples/math.html with HTTP server
  • Math Rendering: Verified inline and display math render correctly
  • Macros: Confirmed custom macros (R, set) work as expected
  • Async Startup: Confirmed proper handling of MathJax 4's async initialization
  • Slide Changes: Verified math re-renders when navigating slides

Browser Compatibility

Tested on modern browsers that support MathJax 4.0.0.

Khlick added 4 commits August 7, 2025 19:59
- Add plugin/math/mathjax4.js with MathJax 4.0.0 support
- Update plugin/math/plugin.js to include MathJax4 export
- Add MathJax4 configuration example in examples/math.html
- Add comprehensive tests in test/test-mathjax4.html
- Rebuild math.js and math.esm.js with new plugin
- Bump version to 5.2.2
- Support for MathJax 4.0.0 async startup procedure
- Compatible macros configuration similar to MathJax3
@rajgoel
Copy link
Copy Markdown
Contributor

rajgoel commented Nov 23, 2025

@Khlick Thanks a lot for the great plugin. Finally, we can combine auto-animate with equations using \data{dataset}{math} introduced with MathJax4:

MathJax4-AutoAnimate

Here's the code for this:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Reveal.js + MathJax 4 + Auto-animate</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <!-- Reveal.js core CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/dist/reveal.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.2.1/dist/theme/black.css">
</head>
<body>
  <div class="reveal">
    <div class="slides">
      <section data-auto-animate>
        <h2>MathJax 4 Example</h2>
        <p>$$\frac{\data{id=numerator}{x} }{y} \cdot y = 1$$</p>
      </section>
      <section data-auto-animate>
        <h2>MathJax 4 Example</h2>
        <p>$$\data{id=numerator}{x} = 1$$</p>
      </section>
    </div>
  </div>

  <!-- Reveal.js core JS -->
  <script src="https://cdn.jsdelivr.net/npm/reveal.js@5/dist/reveal.js"></script>

  <!-- MathJax 4 plugin (ES module) -->
  <script type="module">
    import { MathJax4 } from "https://cdn.jsdelivr.net/gh/Khlick/reveal.js/plugin/math/mathjax4.js";

    Reveal.initialize({
      plugins: [
        MathJax4
      ],
      mathjax4: {
        tex: {
          inlineMath: [['$', '$'], ['\\(', '\\)']],
          displayMath: [['$$', '$$'], ['\\[', '\\]']]
        },
        options: {
          skipHtmlTags: ['script','noscript','style','textarea','pre','code']
        }
      }
    });
  </script>
</body>
</html>

@rajgoel
Copy link
Copy Markdown
Contributor

rajgoel commented Jan 24, 2026

@hakimel Is there anything holding back merging this PR? I wonder whether it makes sense waiting for this or to start using this now by switching to the fork?

@hakimel hakimel merged commit 519d43e into hakimel:master Jan 24, 2026
1 check passed
@hakimel
Copy link
Copy Markdown
Owner

hakimel commented Jan 24, 2026

This PR looks great and there are no blockers for merging.

Thank you very much for adding this, @Khlick!

@rschmehl
Copy link
Copy Markdown
Contributor

Hi all,
Great contribution! What doesn't seem to work is using MathJax fragments (using \class{}{} and \data{}{}) together with regular text fragments. The fragment-indexes are not synced. Here is an example

<section>
<h1>Test how MatJax4 works</h1>
<p>$$
a^2 + \class{fragment}{\data{fragment-index=2}{b^2}} = \class{fragment}{\data{fragment-index=1}{c^2}}
$$</p>
<p>$$
\begin{align}
  (x+1)^2 & \class{fragment}{\data{fragment-index=0}{ = (x+1)(x+1)}}         \\[3px]
          & \class{fragment}{\data{fragment-index=2}{ = x(x+1) + 1(x+1)}}    \\[3px]
          & \class{fragment}{\data{fragment-index=5}{ = (x^2+x) + (x+1)}} \class{fragment}{\data{fragment-index=4}{ + y^2}}   \\[3px]
          & \class{fragment}{\data{fragment-index=3}{ = x^2 + (x + x) + 1}}  \\[3px]
          & \class{fragment}{\data{fragment-index=4}{ = x^2 + 2x + 1}}
\end{align}
$$</p>
<p><span class="fragment" data-fragment-index="5">First final statement</span></p>
<p><span class="fragment" data-fragment-index="6">Second final statement</span></p>
</section>

The MathJax fragments and the regular text fragments appear in parallel. First, we see = (x+1)(x+1) and First final statement appearing, then c^2 and Second final statement, and so on.

@rschmehl
Copy link
Copy Markdown
Contributor

A quick and dirty solution, if someone needs it

<section>
<h1>Test how MatJax4 works</h1>
<p>$$
a^2 + \class{fragment}{\data{fragment-index=2}{b^2}} = \class{fragment}{\data{fragment-index=1}{c^2}}
$$</p>
<p>$$
\begin{align}
  (x+1)^2 & \class{fragment}{\data{fragment-index=0}{ = (x+1)(x+1)}}         \\[3px]
          & \class{fragment}{\data{fragment-index=2}{ = x(x+1) + 1(x+1)}}    \\[3px]
          & \class{fragment}{\data{fragment-index=5}{ = (x^2+x) + (x+1)}} \class{fragment}{\data{fragment-index=4}{ + y^2}}   \\[3px]
          & \class{fragment}{\data{fragment-index=3}{ = x^2 + (x + x) + 1}}  \\[3px]
          & \class{fragment}{\data{fragment-index=4}{ = x^2 + 2x + 1}}
\end{align}
$$</p>

<p><span class="fragment" data-fragment-index="0"></span></p>
<p><span class="fragment" data-fragment-index="1"></span></p>
<p><span class="fragment" data-fragment-index="2"></span></p>
<p><span class="fragment" data-fragment-index="3">First final statement</span></p>
<p><span class="fragment" data-fragment-index="4"></span></p>
<p><span class="fragment" data-fragment-index="5">Third final statement</span></p>
</section>

@rajgoel
Copy link
Copy Markdown
Contributor

rajgoel commented Feb 17, 2026

Correct, I had also experienced this in other use cases. Reveal.js appears to need to know the fragments relatively early when generating the slides. MathJax and other dynamic content is only processed after the fragments are initialized. Creating empty fragments with respective indices is working reliably in such cases (at least to my experience).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants