Temml Administration
Browser Support
Temml works in browsers that support MathML. This includes Chrome, Edge, Firefox, and Safari. Temml will never work in Internet Explorer.
Installation
For use in the browser, you can download a zip file of Temml from the releases page of the Temml repository. For server-side use, you can obtain Temml via CLI commands npm install temml
or yarn add temml
.
The minimum browser installation needs the following files. The css
file and font file must be in the same folder.
temml.min.js
Temml-Local.css
Temml.woff2
A server-side installation should use temml.cjs
or temml.mjs
instead of temml.min.js
.
Starter template
<!DOCTYPE html>
<!-- Temml requires the use of the HTML5 doctype. -->
<html>
<head>
...
<link rel="stylesheet" href="./Temml-Local.css">
<script src="./temml.min.js"></script>
</head>
...
</html>
API
In-Browser, One Element
To render one <math>
element into one DOM element, call temml.render
with a TeX expression and a DOM element to render into:
temml.render("c = \\pm\\sqrt{a^2 + b^2}", element);
To render in display mode, the call would be:
temml.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true });
If the element you provide is a <math>
element, Temml will populate it. Otherwise, it will create a new <math>
element and make it a child of the element you provide.
In-Browser, Bulk
Breaking Change Notice: renderMathInElement
is now part of temml.js
. No extension is necessary.
The renderMathInElement
function is typically used to render all of the math in the text of a running HTML document. It searches all of the text in a given element for your chosen delimiters, and renders the math in place.
A typical call might look like this:
<script>
temml.renderMathInElement(document.main, { fences: "$+" })
</script>
Auto-render details
In an auto-render document, authors write LaTeX within math delimiters. The default delimiters are:
$$…$$
\(…\)
\begin{equation}…\end{equation}
\begin{equation*}…\end{equation*}
\begin{align}…\end{align}
\begin{align*}…\end{align*}
\begin{alignat}…\end{alignat}
\begin{alignat*}…\end{alignat*}
\begin{gather}…\end{gather}
\begin{gather*}…\end{gather*}
\begin{CD}…\end{CD}
\ref{…}
\eqref{…}
\[…\]
The items beginning with \begin{equation}
and ending with \eqref{…}
are from AMS LaTeX.
You can use the fences
option to customize the recognized delimiters.
fences key |
$$…$$ | $`…`$ | $…$ | \[…\] | \(…\) | AMS |
---|---|---|---|---|---|---|
default | ✓ | ✓ | ✓ | ✓ | ||
$ | ✓ | ✓ | ✓ | |||
$+ | ✓ | ✓ | ✓ | ✓ | ||
( | ✓ | ✓ | ||||
(+ | ✓ | ✓ | ✓ | |||
ams | ✓ | |||||
all | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
…or you can use the delimiters
option instead of the fences
option to further customize your delimiters:
The property of a delimiters
option is a detailed list of delimiters. Here is the default:
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "\\(", right: "\\)", display: false },
{ left: "\\begin{equation}", right: "\\end{equation}", display: true },
{ left: "\\begin{equation*}", right: "\\end{equation*}", display: true },
{ left: "\\begin{align}", right: "\\end{align}", display: true },
{ left: "\\begin{align*}", right: "\\end{align*}", display: true },
{ left: "\\begin{alignat}", right: "\\end{alignat}", display: true },
{ left: "\\begin{alignat*}", right: "\\end{alignat*}", display: true },
{ left: "\\begin{gather}", right: "\\end{gather}", display: true },
{ left: "\\begin{gather*}", right: "\\end{gather*}", display: true },
{ left: "\\begin{CD}", right: "\\end{CD}", display: true },
{ left: "\\[", right: "\\]", display: true }
];
If you want to add support for inline math via $…$
, be sure to list it after $$…$$
. Because rules are processed in order, putting a $
rule first would match $$
and treat as an empty math expression.
The renderMathInElement
function recognizes an options object as it’s second argument. This is demonstrated above with fences
. The options argument can include any option used by the temml.render
function. It also recognizes fences
or delimiters
and the following options:
ignoredTags
: This is a list of DOM node types to ignore when recursing through. The default value is["script", "noscript", "style", "textarea", "pre", "code", "option"]
.ignoredClasses
: This is a list of DOM node class names to ignore when recursing through. By default, this value is not set.errorCallback
: A callback method returning a message and an error stack in case of an critical error during rendering. The default usesconsole.error
.preProcess
: A callback function,(math: string) => string
, used to process math expressions before rendering.
Server-Side
To generate a <math>
element on the server or to generate an MathML string of the rendered math, you can use temml.renderToString
:
const temml = require('./temml.cjs'); // if in Node.js
const mathML = temml.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
...and for display mode:
const mathML = temml.renderToString("c = \\pm\\sqrt{a^2 + b^2}", { displayMode: true });
Macro persistence
Authors can write their own macros, but you decide whether macros should persist between calls to temml.render
.
Say that you have an HTMLCollection of elements whose contents should be converted from TeX strings to math. The code for such a conversion might look like this:
Option 1: Macros do not persist between calls to Temml:
// Render all the math.
for (let aSpan of [...mathSpans]) {
const tex = aSpan.textContent;
const displayMode = aSpan.classList.contains("display");
temml.render(tex, aSpan, { displayMode });
}
// Optional postProcess to render \ref{}
temml.postProcess(document.body);
Option 2: Macros defined with \gdef
do persist:
// Optional macros object to hold macros that persist between calls to Temml.
const macros = {}
// Render all the math.
for (let aSpan of [...mathSpans]) {
const tex = aSpan.textContent;
const displayMode = aSpan.classList.contains("display");
// Notice the macros argument below.
// It carries macros that were defined with \gdef or \global\let
temml.render(tex, aSpan, { macros, displayMode });
}
// Optional postProcess to render \ref{}
temml.postProcess(document.body);
Notice that you can choose when to stop macro persistence by redefining macros
.
Option 3: Macros persist and there are some predefined macros:
Now say that you wish to pre-define two macros and a color with document-wide scope.
// Optional preamble to pre-define macros.
const macros = temml.definePreamble(
`\\newcommand\\d[0]{\\operatorname{d}\\!}
\\def\\foo{x^2}
\\definecolor{sortaGreen}{RGB}{128,128,0}`
);
// Render all the math.
for (let aSpan of [...mathSpans]) {
const tex = aSpan.textContent;
const displayMode = aSpan.classList.contains("display");
temml.render(tex, aSpan, { macros, displayMode });
}
// Optional postProcess to render \ref{}
temml.postProcess(document.body);
Preamble
To give document-wide scope to a set of macros or colors, define them in a preamble.
const macros = temml.definePreamble(
`\\newcommand\\d[0]{\\operatorname{d}\\!}
\\def\\foo{x^2}
\\definecolor{sortaGreen}{RGB}{128,128,0}`
);
Any valid Temml macro or \definecolor may be written into a preamble. Then include the resulting macros in the Temml options.
Options
You can provide an object of options as the last argument to temml.render
and temml.renderToString
. For example:
temml.render(
"c = \\pm\\sqrt{a^2 + b^2}",
element,
{ displayMode: true, macros }
);
Available options are:
displayMode
:boolean
. Iftrue
the math will be rendered in display mode, which will put the math in display style (so\int
and\sum
are large, for example), and will center the math on the page on its own line. Iffalse
the math will be rendered in inline mode. (default:false
)macros
:object
. A collection of custom macros. The easy way to create them is via a preamble, noted just above. Alternatively, you can provide a set of key-value pairs in which each key is a new Temml function name and each value is the expansion of the macro. Example:macros: {"\\R": "\\mathbb{R}"}
.annotate
:boolean
. Iftrue
, Temml will include an<annotation>
element that contains the input TeX string. Note:annotate
must be true if you want thecopy-tex
extension to be effective. Also note: Auto-linebreaks will not work if annotation is true. (default:false
)wrap
: ("tex"
|"="
|"none"
). A mode for soft line breaks in non-display mode math. Thetex
option sets a soft line break after every top-level relation and binary operator, per The TeXbook, page 173. The=
option sets a soft line break before the second and subsequent top-level=
signs.tex
is the default.Caveats: Soft line breaks work in Chromium and Firefox, but do not work in WebKit or Safari. Display mode math gets no soft line breaks. Annotated math gets no soft line breaks. If a writer sets a hard line break via
\\
or\cr
, then Temml will not set any soft line breaks in that expression.leqno
:boolean
. Iftrue
, display math has\tag
s rendered on the left instead of the right, like\usepackage[leqno]{amsmath}
in LaTeX. (default:false
)colorIsTextColor
:boolean
. In LaTeX,\color
is a switch, but in early versions of MathJax and KaTeX,\color
applied its color to a second argument, the way that LaTeX\textcolor
works. Set optioncolorIsTextColor
totrue
if you want\color
to work like early MathJax or KaTeX. (default:false
)'throwOnError':
boolean
. If true, Temml will throw parse errors to the console. If false, Temml will write the parse error to the output of therender()
function. (default: false)errorColor
:string
. A color string given in the format"#XXX"
or"#XXXXXX"
. This option determines the color that unsupported commands and invalid LaTeX are rendered in. (default:#b22222
)maxSize
:[number, number]
. This provides a way to cap all user-specified sizes, e.g. in\rule{500em}{500em}
. The first number is the cap inem
units, which will be applied to user-specified relative units. The second number is the cap in CSSpt
units, which will be applied to user-specified absolute units. The default is[Infinity, Infinity]
, which allows users to make elements and spaces arbitrarily large.maxExpand
:number
. Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. (\edef
expansion counts all expanded tokens.) If set toInfinity
, the macro expander will try to fully expand as in LaTeX. (default: 1000)strict
:boolean
. Iffalse
(similar to MathJax), allow features that make writing LaTeX convenient but are not actually supported by LaTeX. Iftrue
(LaTeX faithfulness mode), throw an error for any such transgressions. (default:false
)xml
:boolean
. Iftrue
, Temml will write a namespace into the<math>
element. That namespace isxmlns="http://www.w3.org/1998/Math/MathML"
. Such a namespace is unnecessary for modern browsers but can be helpful for other user agents, such as Microsoft Word. (default:false
)trust
:boolean
orfunction
(default:false
). Iffalse
(do not trust input), prevent any commands like\includegraphics
that could enable adverse behavior, rendering them instead inerrorColor
. Iftrue
(trust input), allow all such commands. Provide a custom functionhandler(context)
to customize behavior depending on the context (command, arguments e.g. a URL, etc.). A list of possible contexts:{command: "\\url", url, protocol}
whereprotocol
is a lowercased string like"http"
or"https"
that appears before a colon, or"_relative"
for relative URLs.{command: "\\href", url, protocol}
{command: "\\includegraphics", url, protocol}
{command: "\\class", class}
{command: "\\id", id}
{command: "\\style", style}
{command: "\\data", attributes}
Here are some sample trust settings:
Forbid specific command:
trust: (context) => context.command !== '\\includegraphics'
Allow specific command:
trust: (context) => context.command === '\\url'
Allow multiple specific commands:
trust: (context) => ['\\url', '\\href'].includes(context.command)
Allow all commands with a specific protocol:
trust: (context) => context.protocol === 'http'
Allow all commands with specific protocols:
trust: (context) => ['http', 'https', '_relative'].includes(context.protocol)
Allow all commands but forbid specific protocol:
trust: (context) => context.protocol !== 'file'
Allow certain commands with specific protocols:
trust: (context) => ['\\url', '\\href'].includes(context.command) && ['http', 'https', '_relative'].includes(context.protocol)
\ref and \eqref
If you are using temml.renderMathInElement
, you can ignore this section. renderMathInElement
handles this automatically.
The postProcess
function implements the AMS functions \ref
and \eqref
. It should be called outside of any loop.
The main Temml functions, temml.render
and temml.renderToString
, each operate on only one element at a time. In contrast, the postProcess
function makes two passes through the entire document. One pass finds the \labels
written in a document and the second pass populates \ref
and \eqref
with the tags or auto-numbers associated with each label.
If you choose not to support \ref
and \eqref
, postProcess
can be omitted.
If Temml is used server-side, \ref
and \eqref
are still implemented at runtime with client-side JavaScript. A small file, temmlPostProcess.js
, is provided to be installed in place of temml.min.js
. It exposes one function:
temml.postProcess(document.body)
If you do not provide a runtime postProcess
, everything in Temml will work except \ref
and \eqref
.
Version
To get the current version of Temml running in the browser, open the console and type:
temml.version
Fonts
Temml has several different pre-written CSS files. You should use only one and by that choice, you also choose a math font. There are several math fonts available and each has different advantages.
Latin Modern will provide the best quality rendering. It is a clone of Computer Modern and so is very home-like for readers accustomed to LaTeX documents. For best results, you must also serve a small (10kb) Temml.woff2
file. Then you’ll get support for \mathscr{…}
and you’ll get primes at the correct vertical alignment in Chrome and Edge.
Temml-Local.css is the light-weight option. It calls three fonts: Cambria Math, which comes pre-installed in Windows, STIX TWO, which comes pre-installed in iOS and MacOS (as of Safari 16), or NotoSans Math, which I think comes pre-installed in Android. The first two need to be augmented with Temml.woff2
.
Sadly, this option has rendering issues. Chrome botches extensible arrows and it will fail to stretch the ∫
symbol on Windows.
Asana and Libertinus have some of the same rendering problems as Cambria Math, although Asana does contain its own roundhand glyphs.
NotoSans Math is a sans-serif math font from Google. I think it comes bundled with Android. Chromium fails to stretch extensible arrows in this font.
Several other math fonts exist and you can try them out at Frédéric Wang’s Mathematical OpenType Fonts.
Where to find font files:
Temml.woff2 can be downloaded with the latest Temml release.
STIXTwoMath-Regular.woff2 is located at the STIX repository.
LibertinusMath-Regular.woff2 is located at the Libertinus repository.
NotoSansMath-Regular.woff2 is located at Google webfonts.
The other fonts can be downloaded at Mathematical OpenType Fonts.
If you want a different math font size, you can add a rule to your own page’s CSS, like this example:
math { font-size: 125%; }
Equation numbering
In order to place automatic equation numbers in certain AMS environments, Temml contains these CSS rules:
.tml-eqn::before {
counter-increment: tmlEqnNo;
content: "(" counter(tmlEqnNo) ")";
}
body { counter-reset: tmlEqnNo; }
You can overwrite the content
rule to produce customized equation numbers. For instance, if chapter three of your book is in its own html file, that file’s <head>
could contain:
<style>
.tml-eqn::before { content: "(3." counter(tmlEqnNo) ")"; }
</style>
Then the automatic equation numbering in that chapter would look like: (3.1)
If your site does not render automatic numbering properly, check if your other CSS has overwritten the Temml counter-reset.
Extensions
More Temml functionality can be added via the following extensions:
copy-tex: When users select and copy
<math>
elements, copies their LaTeX source to the clipboardmhchem: Write beautiful chemical equations easily.
physics: Implement much of the LaTeX
physics
package.texvc: Support functions used in wikimedia.
To install extensions for browser use, include the appropriate file from the contrib
folder of the Temml repository. Then reference the file in the <head>
of the HTML page. As in this mhchem
example:
<head>
...
<link rel="stylesheet" href="./Temml-Local.css">
<script src="./temml.min.js"></script>
<script src="./mhchem.min.js"></script>
</head>
The extension reference must come after the reference to temml.min.js
.
For server-side use, use temml.cjs
or temml.mjs
instead of temml.min.js
. temml.cjs
and temml.mjs
both include mhchem
, physics
, and texvc
.
Security
Any HTML generated by Temml should be safe from <script>
or other code injection attacks.
A variety of options give finer control over the security of Temml with untrusted inputs; refer to Options for more details.
maxSize
can prevent large width/height visual affronts.maxExpand
can prevent infinite macro loop attacks.trust
can allow certain commands that may load external resources or change HTML attributes and thus are not always safe (e.g.,\includegraphics
or\class
)
Browser Issues
If you are deciding whether to render math in MathML, know that all the major browser engines now support MathML. If you want to revel in the sight of over a thousand LaTeX functions rendered well in MathML, head on over to the Temml function support page.
The rest of you, stay here. This section identifies functions that browsers render poorly.
Item | Chromium | Gecko (Firefox) |
WebKit (Safari) |
Examples |
---|---|---|---|---|
Renders well on first paint | ✓ | ✓ | bad¹ | |
Accents | ✓ | ✓ | bad² | |
Integral, ∫, in display mode | meh³ | ✓ | ✓ | |
\left( x \right) | ✓ | ✓ | meh⁴ | |
Tag placement | ✓ | ✓ | poor⁵ | |
Extensible arrows | poor⁶ | ✓ | poor⁶ | |
Radical height | ✓ | meh⁷ | meh⁷ | |
Size 4 radicals | meh⁸ | ✓ | ✓ | |
Line-breaking | ✓ | ✓ | bad⁹ | |
\smash, \mathllap, \mathrlap, CD environment | ✓ | ✓ | bad¹⁰ | |
= does not get operator spacing when between text | meh | meh | ✓ |
Notes:
WebKit renders some things correctly only after a page refresh.
WebKit renders some accents too high. Temml does some work to mitigate this. It’s not enough.
Chromium does not stretch a Cambria Math ∫ in display mode. Latin Modern is okay.
WebKit mis-aligns short parentheses, given a \left and \right.
WebKit mis-locates tags and AMS automatic equation numbers because it ignores
width: 100%
on an<mtable>
.Chromium and WebKit system font extensible arrows have notes placed too high. Some do not stretch in Cambria Math or NotoSans. Again, Latin Modern is okay.
Firefox and WebKit sometimes select radicals that are too tall. (Root cause: They don’t cramp subscripts and superscripts.)
In very tall radicals, Chromium does not accurately match the vinculum to the surd.
Automatic linebreaking (non-display mode) works in Chromium and Firefox. Not in WebKit.
WebKit fails to render anything inside the
<mpadded>
element.
You can suggest revisions to this page at the Temml issues page.
Copyright © 2021-2025 Ron Kok. Released under the MIT License