MathJax, Macros and Packages. Tex simplified commands

Logo

Introduction

If you are not used to Latex documents and started to publish scientific documents only using HTML language and MathJax javascript library, you are quickly faced to heavy and repetitive syntaxes, example :

$$ \dfrac{dH}{dp} = \left( \dfrac{\partial H}{\partial T} \right)_p \dfrac{dT}{dp} + \left( \dfrac{\partial H}{\partial p} \right)_T $$
<div class="cmath">
  $$
      \dfrac{dH}{dp} = \left( \dfrac{\partial H}{\partial T} \right)_p \dfrac{dT}{dp}
                      + \left( \dfrac{\partial H}{\partial p} \right)_T
  $$
</div>

In the above example, we want to simplify and automate normal and partial derivatives using shortcut commands.

Another example, we want to automate and normalize units writing and to create shortcuts for physics constants used in several pages :

$$ \begin{align} g &= 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} \\ R &= 8.3145 \ \mathrm{J\!\cdot\!mol\small{^{-1}}\!\cdot\!K\small{^{-1}}} \end{align}$$
<div class="cmath">
  $$
    \begin{align} 
      g &= 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}}   \\ 
      R &= 8.3145 \ \mathrm{J\!\cdot\!mol\small{^{-1}}\!\cdot\!K\small{^{-1}}}
    \end{align}
  $$
</div>

To achieve it, MathJax javascript library supports Tex macros commands (\def, \newcommand, \let…).

MathJax v2 and v3 loading configurations are given in the appendix. In this paper, Tex code is encapsulated in div, ins and span HTML tags having the class cmath. Delimiters are :

  • Block mode : $$ Tex code $$, \[ Tex code \]
  • Inline mode : ## Tex code ##, \( Tex code \)
<div class="cmath"> $$  Tex code $$ </div>
<span class="cmath"> ... \( Tex code \) ... </span>

New to MathJax and Tex ? A quick reference guide is available on this portal : SQLPAC | MathJax - Tex : Quick Reference Guide

Prerequisites

Macros are enabled by default in MathJax 2 and MathJax 3.

With MathJax 3, if a minimalist configuration has been decided, macros must be enabled in the window.MathJax object by adding the newcommand and configmacros packages. The configmacros package is needed only if it is planned later to define macros in the window.MathJax object :

<script>
  window.MathJax = {
   tex: {
     …,
     packages: ['base','newcommand','configmacros','noerrors']
   },
   …,
   loader: {
     load: ['input/tex-base','output/chtml','[tex]/newcommand','[tex]/configmacros','[tex]/noerrors']
   }
</script>
<script src="[path_to_mathjax]/startup.js" id="MathJax-script">

A basic macro

\( \def \Cg { 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} } % Gravitational constant \)

Initiate a "hidden" tag to store macros definitions using CSS, in this paper the ins tag having the class cmath:

ins[class*="cmath"] {
    position: fixed; top: 10px; height: 0px; width: 0px;
    color: transparent; background-color: transparent;
}

Do not use the CSS property display: none, otherwise the MathJax v3.2 new lazy mode feature won’t work, this feature uses the IntersectionObserver object.

A Tex shortcut Cg is now created for the gravitational constant ##g##. In the "hidden" tag, using \def :

<ins class="cmath">
  \( \def \Cg { 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} }   % Gravitational constant \)
</ins>

In Tex code, just call \Cg :

<div class="cmath">$$ \Cg{} $$</div>
$$ \Cg{} $$

Instead of using a "hidden" tag, macros can be defined in the window.MathJax object before calling MathJax, backslashes are escaped :

MathJax v2
window.MathJax = {
 …,
 TeX : {
  Macros : {
   Cg : "9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}}"
  }
 }
}
MathJax v3
window.MathJax = {
 tex : {
  …,
  macros : {
   Cg : "9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}}"
  }
 }
 …
}

This example is very basic, values and units are hard coded. Of course macros handle arguments.

Macros with arguments

Let’s define 2 macros dvr and dvp respectively for regular and partial derivatives : 2 arguments in the macros.

\( \def \dvr #1#2 { \dfrac{d#1}{d#2} } % Regular derivative) \) \( \def \dvp #1#2 { \dfrac{\partial #1}{\partial #2} } % Partial derivative) \)
<ins class="cmath">
  \( \def \dvr #1#2 { \dfrac{d#1}{d#2} }   % Regular derivative \)
  \( \def \dvp #1#2 { \dfrac{\partial #1}{\partial #2} }   % Partial derivative \)
</ins>

The equation in the introduction is now simply written and even more readable provided you know your own macros well :

<div class="cmath">
  $$ 
    \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} +  \left( \dvp{H}{p} \right)_T
  $$
</div>
$$ \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} + \left( \dvp{H}{p} \right)_T $$

The maximum number of arguments in the \def command is 9 : from #1 to #9.

By default, defining \def \dvp #1#2#3 { … }, the syntax \dvp{ }{ }{ } is expected in the Tex code. In an alternate syntax, the first argument is delimited by square brackets while the others are single characters :

\( \def \drv[#1]#2 { \dfrac{d#1}{d#2} } % Derivative) \)
<ins class="cmath">
  \( \def \drv[#1]#2 { \dfrac{d#1}{d#2} }   % Derivative) \)
</ins>
<div class="cmath">$$  \drv[T]{p}  $$</div>
$$ \drv[T]{p} $$

The \def command does not understand optional arguments. For optional arguments, use \newcommand instead, but support is partial, only one optional argument is allowed : this topic is addressed in the next sections.

\def does not check whether the command already exists, definition is overwritten. Existence checks are possible :

\( \ifx \dv \undefined \def \dvr #1#2 { \dfrac{d#1}{d#2} }   % Regular derivative \fi \)

Defining macros with \newcommand

Instead of the \def command to define macros, \newcommand may be prefered. What are the differences ?

  • \newcommand fails if the command is already defined.
  • \newcommand provides a convenient syntax for specifying the number of arguments and an optional argument (only one).
  • \newcommand defines "long" commands, \def defines short ones unless \long\def is used.

To sum up the \newcommand basic syntax :

\newcommand {\cmd}[number of arguments] { ...#1...#2... }

The demo equation with \newcommand is now :

\( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} } % Regular derivative \) \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} } % Partial derivative \)
<ins class="cmath">
   \( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} }   % Regular derivative \)
   \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} }   % Partial derivative \)            
</ins>
<div class="cmath">
  $$ 
    \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} +  \left( \dvp{H}{p} \right)_T
  $$
</div>
$$ \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} + \left( \dvp{H}{p} \right)_T $$

To define the macros in the window.MathJax object :

MathJax v2
window.MathJax {
 …,
 TeX : {
  Macros : {
    dvr: ["{ \\dfrac{d#1}{d#2} }",2],
    dvp: ["{ \\dfrac{\\partial{#1}}{\\partial{#2}} }",2]
  }
 }
}
MathJax v3
window.MathJax {
 tex : {
  …,
  macros : {
    dvr: ["{ \\dfrac{d#1}{d#2} }",2],
    dvp: ["{ \\dfrac{\\partial{#1}}{\\partial{#2}} }",2]
  }
 }
 …
}

Optional argument

With \newcommand, we can define one optional argument, and only one.

The syntax is then :

\newcommand {\cmd}[number of arguments][default value optional argument] { ...#1...#2... }
  • The optional argument is always #1.
  • To set a value for the optional argument when calling the command : \cmd[value]{}....
<ins class="cmath">
  \( \newcommand {\seq}[2][n] { S_{#1} = #2_0 + #2_1 + \cdots + #2_{#1}}   % Sequences \) 
</ins>
<div class="cmath">
  $$
     \seq{u}    \\
     \seq[n-1]{u} \\
     \seq[j]{a}
  $$
</div>
\( \newcommand {\seq}[2][n] { S_{#1} = #2_0 + #2_1 + \cdots + #2_{#1}} % Sequences \)
$$\displaylines { \seq{u} \\ \seq[n-1]{u} \\ \seq[j]{a} }$$

Combining macros

Macros can be combined and nested. The definition order does not matter, evaluation is not performed at the definition step.

In the below example, big left and right parenthesis are automated using macros :

\( \newcommand {\bdvr}[2] { \left( \dvr{#1}{#2} \right) } % Regular derivative Big parenthesis \) \( \newcommand {\bdvp}[2] { \left( \dvp{#1}{#2} \right) } % Partial derivative Big parenthesis \) \( \newcommand {\bp}[1] { \left( #1 \right) } % Big parenthesis \)
<ins class="cmath">
   \( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} }   % Regular derivative \)
   \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} }   % Partial derivative \)
   \( \newcommand {\bdvr}[2] { \left( \dvr{#1}{#2} \right)   % Regular derivative Big parenthesis \)
   \( \newcommand {\bdvp}[2] { \left( \dvp{#1}{#2} \right) }   % Partial derivative Big parenthesis \)
   \( \newcommand {\bp}[1] { \left( #1 \right) }   % Big parenthesis \)            
</ins>
<div class="cmath">
  $$ 
    \dvr{H}{p} = \bdvp{H}{T}_p \dvr{T}{p} +  \bdvp{H}{p}_T
  $$
</div>

or, using bp macro :

<div class="cmath">
  $$ 
    \dvr{H}{p} = \bp{\dvp{H}{T}}_p \dvr{T}{p} +  \bp{\dvp{H}{p}}_T
  $$
</div>
$$ \dvr{H}{p} = \bp{\dvp{H}{T}}_p \dvr{T}{p} + \bp{\dvp{H}{p}}_T $$

Knowing how to combine macros, how to define an optional argument, units formatting and physics constants definitions become easier : 3 macros

  • \unit : to format the whole unit (font, space).
  • \per : to format minus x power, by default ##-1##.
  • \pt : to format the dot separator in the unit.
\( \newcommand {\unit}[1] {\ \mathrm{#1}} % Unit format (font, space) \) \( \newcommand {\pt}{\!\cdot\!} % Unit dot separator formatting \) \( \newcommand {\per}[1][1]{\small{^{-#1}}} % Minus x power \)
<ins class="cmath">
  \( \newcommand {\unit}[1] {\ \mathrm{#1}}   % Unit format (font, space) \)
  \( \newcommand {\pt}{\!\cdot\!}   % Unit dot separator formatting \)
  \( \newcommand {\per}[1][1]{\small{^{-#1}}}   % Minus x power \)            
</ins>

The 2 constants ##R## and ##g## are now coded and displayed using these reusable macros :

<div class="cmath">
  $$
   \begin{align}
      R &= 8.3145 \unit{J \pt mol\per \pt K\per} \\
      g &= 9.81 \unit{m \pt s\per[2]}
   \end{align}
  $$ 
</div>
$$\begin{align} R &= 8.3145 \unit{J \pt mol\per \pt K\per} \\ g &= 9.81 \unit{m \pt s\per[2]} \end{align} $$

We may now decide to define the physics constants called in several pages using macros, moreover a uacc macro is created for the acceleration unit (##\unit{m \pt s\per[2]}##), unit used in many pages :

\( \newcommand {\uacc}{ \unit{m \pt s\per[2]} } % Acceleration unit \) \( \newcommand {\CR}{ 8.3145 \unit{J \pt mol\per \pt K\per} } % Ideal gas constant \) \( \newcommand {\Cg}{ 9.81 \uacc} % Gravitational constant \)
<ins class="cmath">
   \( \newcommand {\uacc}{ \unit{m \pt s\per[2]} }   % Acceleration unit \)
   \( \newcommand {\CR}{ 8.3145 \unit{J \pt mol\per \pt K\per} }   % Ideal gas constant \)
   \( \newcommand {\Cg}{ 9.81 \uacc}     % Gravitational constant \)
</ins>
<div class="cmath">
  $$
   \begin{align}
      R &= \CR \\
      g &= \Cg
   \end{align}
  $$ 
</div>
$$\begin{align} R &= \CR \\ g &= \Cg \end{align} $$

If the macros are defined in the window.MathJax object :

MathJax v2
window.MathJax = {
 …,
 TeX : {
  Macros : {
   unit: ["{ \\ \\mathrm{#1} }",1],
   pt:   ["{ \\!\\cdot\\! }"],
   per:  ["{ \\small{^{-#1}} }",1,"1"],
   uacc: ["{ \\unit{m \\pt s\\per[2]} }"],
   CR:   ["{ 8.3145 \\unit{J \\pt mol\\per \\pt K\\per} }"],
   Cg:   ["{ 9.81 \\uacc }"]    
  }
 }
}
MathJax v3
window.MathJax = {
 tex : {
  …,
  macros : {
   unit: ["{ \\ \\mathrm{#1} }",1],
   pt:   ["{ \\!\\cdot\\! }"],
   per:  ["{ \\small{^{-#1}} }",1,"1"],
   uacc: ["{ \\unit{m \\pt s\\per[2]} }"],
   CR:   ["{ 8.3145 \\unit{J \\pt mol\\per \\pt K\\per} }"],
   Cg:   ["{ 9.81 \\uacc }"]    
  }
 }
 …
}

Notice : in the per macro, the third argument is the macro’s optional argument default value and it must be a string. If default values datatypes are not string (integer, float, etc.), macros definitions fail with MathJax.

Building and loading macros libraries

In the previous sections, macros are defined in the HTML page or in the window.MathJax object :

HTML
<ins class="cmath">
   \( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} } \)
   \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} } \)
</ins>
window.MathJax - MathJax v3
window.MathJax {
 tex : {
  macros : {
    dvr: ["{ \\dfrac{d#1}{d#2} }",2],
    dvp: ["{ \\dfrac{\\partial{#1}}{\\partial{#2}} }",2]
  }
 }
}

In the HTML option, commands are hard coded in each page which needs the macros. In the window.MathJax option, depending on how MathJax is called (call in the page or using a global function) : either macros are hard coded in the page or all macros are loaded even those not necessary.

A more robust solution consists in splitting macros in files per features, a kind of libraries : for example, 1 file for units management macros, 1 file for derivatives/inegrals macros, etc. In the page, only the necessary libraries are loaded. How to achieve it ?

Using PHP, easy but it needs a Web server : just include the necessary files. Files will store the HTML code which encapsulates the macros definitions.

<body>
  <?php
  require_once('./lib/macros-units.inc');
  require_once('./lib/macros-derivatives.inc');
?>
  …
</body>
./lib/macros-units.inc
<ins class="cmath">
  \( \newcommand {\unit}[1] {\ \mathrm{#1}}  % Unit format (font, etc.) \)
  \( \newcommand {\pt}{\!\cdot\!}  % Unit dot separator formatting \)
  \( \newcommand {\per}[1][1]{\small{^{-#1}}}   % Minus x power \)
  \( \newcommand {\uacc}{ \unit{m \pt s\per[2]} }  % Acceleration unit \)
  \( \newcommand {\CR}{ 8.3145 \unit{J \pt mol\per \pt K\per} }   % Ideal gas constant R \)
  \( \newcommand {\Cg}{ 9.81 \uacc} }   % Gravitational constant \)
  …
</ins>

Using Javascript, a little bit more tricky :

macros definitions must be loaded just after window.MathJax is instantiated and before MathJax runs. Use the defer attribute to guarantee the sequence order, async mode is then no more appropriate.
<head>
 <script>
    window.MathJax = { tex: …, loader: …, … }
 </script>

 <script src="./lib/macros-units.js" defer></script>
 <script src="./lib/macros-derivatives.js" defer></script>
 
 <script src="[path_mathjax]/tex-chtml.js" defer></script>
</head>
./lib/macros-units.js (MathJax v3)
macros = {
   unit: ["{ \\ \\mathrm{#1} }",1],
   pt:   ["{ \\!\\cdot\\! }"],
   per:  ["{ \\small{^{-#1}} }",1,"1"],
   uacc: ["{ \\unit{m \\pt s\\per[2]} }"],
   CR:   ["{ 8.3145 \\unit{J \\pt mol\\per \\pt K\\per} }"],
   Cg:   ["{ 9.81 \\uacc }"]
};

window.MathJax = window.MathJax || {};

m = window.MathJax;

m.tex = m.tex || {};
m.tex.macros = m.tex.macros || {};

m.tex.macros = {...m.tex.macros,...macros};
For MathJax v2, replace m.tex by m.Tex and m.tex.macros by m.Tex.Macros.

MathJax v3 packages

More flexible than version 2, MathJax v3 provide new packages containing useful macros : physics, braket packages. More packages to come in next v3 releases. Regularly, consult the next versions, a new package may match to its needs : no need to reinvent the wheel.

All the macros created above for regular and partial derivatives have analogous equivalents in the physics package included in MathJax 3.

The physics package is not loaded by default, to load it (output is alleviated for brevity) :

window.MathJax = {
  tex: { …, packages: {'[+]': ['noerrors','physics']} },
  …,
  loader: { load: ['[tex]/noerrors','[tex]/physics',…] }        
}

The demo equation in this paper is then the following using physics package : (doc: CTAN - The Physics package) :

<div class="cmath">
  $$
    \dv{H}{p} = \left( \pdv{H}{T} \right)_p \dv{T}{p} + \left( \pdv{H}{p} \right)_T
  $$
</div>

Regular and partial derivatives are respectively managed with \dv and \pdv macros in this package.

And why not applying the bp macro created in previous sections to manage big parenthesis :-) ?

<div class="cmath">
  $$
    \dv{H}{p} = \bp { \pdv{H}{T} }_p \dv{T}{p} + \bp { \pdv{H}{p} }_T
  $$
</div>
$$ \dv{H}{p} = \bp { \pdv{H}{T} }_p \dv{T}{p} + \bp { \pdv{H}{p} }_T $$

Another example, the mhchem package for chemistry equations using \ce macro :

<div class="cmath"> $$ \ce{SO4^2- + Ba^2+ -> BaSO4 v} $$ </div>
$$ \ce{SO4^2- + Ba^2+ -> BaSO4 v} $$

Appendix - Loading MathJax, basic configuration

MathJax v2
<head>
 <script>
    window.MathJax = {
      tex2jax : {
        inlineMath : [ ['##','##'], ["\\(","\\)"] ],
        displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
        processEscapes: true,
        processClass: 'cmath|dmath'
      },
      displayAlign: "left"
    };
 </script>
 <script async="true" 
    src="[path_mathax]/MathJax.js?config=TeX-AMS_CHTML">
 </script>
</head>
MathJax v3.2
<head>
 <script>
    window.MathJax = {
      tex: {
        inlineMath: [ ['##','##'], ["\\(","\\)"] ],
        displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
        processEscapes: true,
        packages: {'[+]': ['noerrors']}
      },
      chtml: {
        displayAlign: "left"
      },
      options: {
        processHtmlClass: 'cmath|dmath',
        ignoreHtmlClass: 'tex2jax_ignore'
      },
      loader: {
        load: ['input/tex','output/chtml','[tex]/noerrors','ui/lazy']
      }
    };
 </script>
 <script async="true"
        src="[path_mathjax]/startup.js"></script>
</head>