Guide and reference
Math rendering
Configure MathJax and accessible math for each loading option.
From the pie-players documentation · View source(opens in new tab)
How <pie-item-player> and the PIE elements it renders typeset math under each
loading strategy, where MathJax loads its fonts and
speech data from, and which MathJax builds can share a page. For hosts that
choose a strategy, self-host element assets, or run MathJax for their own
content.
The MathJax adapter is @pie-element/shared-math-rendering-mathjax, the
pie-elements-ng package through which element builds and the item player run
MathJax 4. Each element pins its adapter version exactly in its
package.json, and several behaviors below depend on that version.
Math Rendering in pie-elements-ng
covers the producer side.
Renderers by strategy
| Strategy | Element math | Item markup math |
|---|---|---|
iife |
The element bundles read the MathJax 3.2.2 renderer the player installs on window["@pie-lib/math-rendering"] (strategy="iife") |
The same renderer |
esm |
Each element hands its math to a renderer on window["@pie-lib/math-rendering"] when the page has one, and otherwise runs MathJax 4.1.3 itself |
The page's renderer, otherwise the player's own MathJax 4.1.3 |
preloaded |
As esm, with the builds the host installed |
As esm |
Item markup math
Each element typesets the math in its own subtree. The player typesets the math
in the rest of the item and passage markup, handing a renderer only the parts
that hold math and no element, so no element's content is typeset twice. It
typesets once the elements are initialized and again when a markup block is
replaced. load-complete waits for
the first pass, so a host that reveals the item on it shows the markup's math
typeset.
The renderer is the page's, window["@pie-lib/math-rendering"]: under iife
the one the player installs, under esm and preloaded one the host installs,
which ESM elements render with as well. On a page without one, the player
imports a MathJax 4.1.3 of its own on the first markup that holds math: the
browser build of the MathJax adapter, which ESM elements bundle. Like the
elements' copies, it neither reads nor writes window.MathJax or the page
renderer, and it loads its fonts and speech data as
MathJax assets sets out.
MathJax assets
Copies of the MathJax adapter from 0.1.3, in the elements and in the player's own MathJax, load MathJax's fonts and speech data as math renders, and on the adapter's npm build MathJax itself. No build names a CDN host. A copy loads each file from:
- Its URL in
window["@pie-lib/math-rendering@2"].opts.assetUrls, keyed by npm path, such as@mathjax/mathjax-newcm-font@4.1.3/chtml/woff2/mjx-ncm-n.woff2. The browser build reads it. - Otherwise the asset root, an npm root: a URL under which
<package>@<version>/<path>serves that file of the package. A copy takes the first ofopts.assetRoot; for the player's own MathJax underesm, the npm root of the element CDN (esmCdnUrlfor jsDelivr,https://raw.esm.shfor esm.sh, the root of a provider object'spackageJsonUrllayout when it has one); and the npm root of the URL the copy loaded from.
Under esm the files come from the CDN the elements load from, with no
configuration. A generated preloaded-player build
lists every file it ships in assetUrls, each by
new URL("./mathjax/npm/…", import.meta.url), so it needs no root and a host
bundler emits the files, given the configuration Vite's dev server and
Angular's webpack builder need (Usage).
A host that registers ESM builds it bundles itself
passes the files' location through registerPreloadedElements
(Registering elements from npm):
registerPreloadedElements(entries, {
math: {
assetRoot: "https://assets.example.com/npm",
speechLocales: ["en", "es"],
},
});
assetRootis the npm root. A self-hosted one serves the files Math Rendering in pie-elements-ng lists, for the packages the adapter'spie.assetPackagesnames. A relative URL resolves against the page.assetUrlsmaps npm paths to the URLs of those files, a string or aURLeach; the files it does not list load from the root.speechPathis the directory ofspeech-worker.jsand itsmathmaps/, by defaultmathjax@<version>/sreunder the root. A directory of its own serves locales that SRE (the Speech Rule Engine, MathJax's speech component) does not ship.speechLocalesare the locales the speech language menu lists, as ids or as ids mapped to their labels; by default every locale SRE ships. List only those that can load.inTabOrder: trueputs typeset math in the keyboard tab order, a tab stop on each expression, for the MathJax menu's setting and its explorer; unset orfalse, math stays out of it. A copy reads it as it starts MathJax, at its first math load, so a later change reaches only copies that have not started. A host that loads a generated preloaded-player build, whose entry registers its elements itself, setsopts.inTabOrderon the page before the entry evaluates, and the entry's registration keeps it. Theiifestrategy's MathJax 3 renderer, a MathJax the host loads and configures itself, and adapter 0.1.4 and earlier ignore it.
The call writes the options it is given to
window["@pie-lib/math-rendering@2"].opts, adds its assetUrls to those the
page lists, and keeps the page options it leaves unset. A host without the
players sets the same page options before the first element renders.
With neither a root nor the fonts' URLs, a copy warns once and dispatches
pie-mathjax-no-asset-root on window: the browser build renders without web
fonts and speech, and the npm build loads no MathJax. Players with
trackPageActions on forward the event to instrumentation once per provider.
Copies up to adapter 0.1.2 ignore the options and load from jsDelivr. The
origins these files add to a Content-Security-Policy are in
security.
The iife strategy's MathJax 3 renderer loads its speech rules, SRE 4.1.2's
mathmaps, from opts.assetRoot when the page sets one, otherwise from the
item player's ESM CDN, jsDelivr by default. A page that configures SRE itself,
through window.SREfeature.json or a text/x-sre-config block naming json,
keeps its own path. Its fonts load from unpkg.com, a URL
@pie-lib/math-rendering-module hard-codes.
One MathJax version per page
The page's window.MathJax holds one MathJax major version, and which builds
typeset on it decides what a page can combine. These builds, page-global below,
typeset on window.MathJax:
- The
iifestrategy's renderer, MathJax 3.2.2, and the same renderer in a@pie-players/pie-preloaded-playerbuild that carries an IIFE bundle (pie-elements-bundle-<hash>.jsbesidemath-rendering.js). - ESM element builds whose MathJax adapter is 0.1.1 or earlier. They load
MathJax 4.1.3 into
window.MathJax, or typeset with the MathJax the page already has. - A host's own MathJax.
ESM element builds whose adapter is 0.1.2-next.20261003161149 or later bundle a
MathJax 4.1.3 private to the module: it neither reads nor writes
window.MathJax, and every element package on the page starts its own copy,
with its own <style id="PIE-MJX-CHTML-styles-<n>">. From 0.1.3 each copy loads
its files from the asset root. @pie-element/multiple-choice
14.0.0, for one, pins adapter 0.1.1. esm loads the build of the version the
item names, preloaded runs the builds the host installed, and a generated
preloaded-player build that bundles ESM builds carries the versions its manifest
lists.
Math Rendering in pie-elements-ng
describes both adapter builds.
ESM builds run MathJax 4 because MathJax 3 ships no ES modules and depends on
the window.MathJax global, and npm marks mathjax-full deprecated in favor of
@mathjax/src. MathJax 3 and MathJax 4 on window.MathJax together is
unsupported: an iife item player next to esm or preloaded elements that
typeset on the page global, or a host's own MathJax 3 next to them. The player
still attempts to render such a page and guarantees nothing about the result.
Elements with their own MathJax run beside a host's MathJax 3 that typesets only
its own content.
In Chromium, mixed pages fail in these ways:
- An
iifeitem loaded after MathJax 4 fails at its math-rendering step withMathJax.loader.preLoad is not a function, so the whole item fails to load. Page-global builds only; a bundled MathJax leaveswindow.MathJaxunset. - MathJax 3 loaded after MathJax 4 overflows the stack during its startup, and later math stays untypeset. Page-global builds only; MathJax 3 loaded after a bundled MathJax starts and typesets normally.
- ESM elements on a page that already runs MathJax 3 typeset with that MathJax
and its configuration, so PIE's macros such as
\longdivrender as errors. Page-global builds only; a bundled MathJax typesets with its own configuration and macros. - Page-global and bundled ESM builds alike hand their math to a renderer on
window["@pie-lib/math-rendering"]when the page has one. After aniifeitem player installs its MathJax 3 renderer there, ESM elements typeset through it, which carries the macros, so an element with its own MathJax typesets with MathJax 3 on that page. - MathJax 3 typesetting the page after ESM math rendered typesets MathJax 4's hidden MathML again, so formulas show twice. Page-global and bundled builds alike: the hidden MathML is in the page's DOM either way.
- MathJax 3 writes its styles to
<style id="MJX-CHTML-styles">, and so does the MathJax 4 that adapters 0.1.1-next.4 and earlier load; with those, the version that renders second removes the other's stylesheet, and math the first one rendered loses its layout. Later adapters write to their own stylesheet,PIE-MJX-CHTML-styleson the page global andPIE-MJX-CHTML-styles-<n>bundled, which MathJax 3 leaves in place. MathJax 3's stylesheet still matches themjx-*elements of both and tightens their spacing.
The MathJax adapter reports a mixed page. When window.MathJax is a MathJax 3
build (mathjax-3-global), or another MathJax output stylesheet sits beside its
own (foreign-output-stylesheet), it logs one console error per page and
dispatches pie-mathjax-version-conflict on window once per condition, with
condition, message and docsUrl in its detail. Players with
trackPageActions on forward it to instrumentation once per provider.
A host that runs MathJax 3 for its own content keeps PIE on iife, or uses
element builds with their own MathJax and typesets only its own containers.