& in \class in aligned

40 views
Skip to first unread message

Andrew Murdza

unread,
Aug 19, 2025, 4:47:37 PMAug 19
to MathJax Users
This is similar to my question about underbrace: how I can use & in a \class macro that is itself in an aligned environment?

Davide Cervone

unread,
Aug 21, 2025, 8:01:57 AMAug 21
to mathja...@googlegroups.com
I'm going to respond to this one first because the overline question has additional issues to be considered.  Also, since you haven't given any actual examples of what you are trying to do, I am making assumptions about what you are trying to accomplish.

As in LaTeX, you generally can't have macros that span entries in a table (which is what underlies the alignment environments).  You need to do some trickery to make that possible.  One approach is to write a macro that splits its argument into two at the ampersand and wraps both in separate \class macro calls.  For example:

\newcommand{\rowClass}[2]{\rowClassParts{#1}#2\endparts}
\def\rowClassParts#1#2&#3\endparts{\class{#1}{#2}&{}\class{#1}{#3}}

defines a \rowClass macro that takes two arguments, the class to use and a row of an alignment, and calls another macro, \rowClassParts, to split the second argument into two parts at the ampersand and wraps each in a \class call with the given class.  That way

\begin{aligned}
\rowClass{myClass}{a&=b+c} \\
&=c+d\\
\end{aligned}

will apply myClass to the a and the = b + c.  The extra {} before the second class is to make the spacing around the equal sign be correct.

Perhaps that is what you are looking for?

Davide


On Aug 19, 2025, at 4:47 PM, Andrew Murdza <andrew...@gmail.com> wrote:

This is similar to my question about underbrace: how I can use & in a \class macro that is itself in an aligned environment?

--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/mathjax-users/7aba2e4f-7125-4cd6-8194-7787ccfff5f0n%40googlegroups.com.

Message has been deleted
Message has been deleted

Andrew Murdza

unread,
Aug 22, 2025, 7:49:19 PMAug 22
to MathJax Users
When I try your code for \begin{aligned}\rowClass{x&=1}\end{aligned} it says "Misplaced &"
You can see the site here: https://lendalcalc.com/tester/tester

Davide Cervone

unread,
Aug 22, 2025, 7:52:21 PMAug 22
to mathja...@googlegroups.com
You need to pass \rowClass TWO parameters, the first being the class to apply to the row and the second being the row of the alignment.  You have used the row as the class name.

Davide


Message has been deleted
Message has been deleted

Andrew Murdza

unread,
Aug 27, 2025, 5:13:47 PMAug 27
to MathJax Users
I realized I missed the class part of the command. However, I tried this and it said Runaway argument for "\rowClassParts?" 
\\let\\oldclass\\class\\renewcommand{\\class}[2]{\\rowClassParts{#1}#2\\endparts}\n' +
'\\def\\rowClassParts#1#2&#3\\endparts{\\oldclass{#1}{#2}&{}\\oldclass{#1}{#3}}

$x=1$ and $\a{\rowClass{blue}{x&=1}}$
Also, I noticed that even \rowParts also doesn't work when there is no &. Is there a way to make \class work in both cases?

Andrew Murdza

unread,
Aug 27, 2025, 5:14:07 PMAug 27
to MathJax Users
Actually as for my previous message (which was deleted by google groups) I can use my custom parser to replace \class with \rowClass if its second argument has an '&' so it isn't an issue. I can do the same for \underbrace{#1}_{#2} when #1 has an '&.' I'm wondering if there is a way to do this with MathJax's preFilters because it will be harder to implement `\underbrace{#1}_{#2}\to rowUnderbrace[#1]{#2}` in the code I have now.
On Friday, August 22, 2025 at 7:52:21 PM UTC-4 Davide Cervone wrote:

Davide Cervone

unread,
Aug 27, 2025, 6:21:06 PMAug 27
to mathja...@googlegroups.com
Here are some definitions that will allow it to handle an argument with an ampersand and also without.

\let\oldclass=\class
\renewcommand{\class}[2]{\rowClassParts{#1}#2&&\endparts}
\def\rowClassParts#1#2&#3&#4\endparts{\oldclass{#1}{#2}\checkEmpty#4\notEmpty\skipEmpty\endCheck{&{}\oldclass{#1}{#3}}}
\def\checkEmpty#1#2#3\endCheck{#2}
\def\skipEmpty#1{}
\def\notEmpty#1{#1}

You have to work a bit to handle a conditional since MathJax doesn't have the low-level macros for that.

Davide


Message has been deleted
Message has been deleted

Andrew Murdza

unread,
Aug 29, 2025, 3:26:27 PMAug 29
to MathJax Users
Thank you Davide! Will this code also work for Mathtip since it also has two arguments like \class? Also is it possible to make one for \bbox? It is different because the first argument is an optional argument (you can assume that the argument will always be provided, but it has [...] not {...}. If needed the new command can use {...} instead of [...]

Andrew Murdza

unread,
Aug 29, 2025, 3:28:21 PMAug 29
to MathJax Users
When I add
MathJax.tex2mml(`\\let\\oldclass=\\class
\n\\renewcommand{\\class}[2]{\\rowClassParts{#1}#2&&\\endparts}
\n\\def\\rowClassParts#1#2&#3&#4\\endparts{\\oldclass{#1}{#2}\\checkEmpty#4\\notEmpty\\skipEmpty\\endCheck{&{}\\oldclass{#1}{#3}}}
\n\\def\\checkEmpty#1#2#3\\endCheck{#2}
\n\\def\\skipEmpty#1{}
\n\\def\\notEmpty#1{#1}`);

Everything with \class becomes a recursive macro call. This is my minimal example.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<style>
.blue{color:blue}
body{
margin:100px;
}
</style>
<script>
window.MathJax ={
loader: {
load: ['[tex]/texhtml']
},
tex: {
packages: {'[+]': ['texhtml']},
},
startup: {
ready: () => {
MathJax.startup.defaultReady();
MathJax.tex2mml(`\\let\\oldclass=\\class
\n\\renewcommand{\\class}[2]{\\rowClassParts{#1}#2&&\\endparts}
\n\\def\\rowClassParts#1#2&#3&#4\\endparts{\\oldclass{#1}{#2}\\checkEmpty#4\\notEmpty\\skipEmpty\\endCheck{&{}\\oldclass{#1}{#3}}}
\n\\def\\checkEmpty#1#2#3\\endCheck{#2}
\n\\def\\skipEmpty#1{}
\n\\def\\notEmpty#1{#1}`
);
},
}
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js"></script>
</head>

<body class="antialiased">
<p>\(x=1\) \(\class{blue}{1}\) \(\begin{aligned}\class{blue}{1&=1}\end{aligned}\)</p>
</body>
</html>

Also in my previous message I asked if the same thing can be done for \underbrace{1&=1}_{1} and \underbrace{1=1}_{1}.

Davide Cervone

unread,
Aug 30, 2025, 8:04:17 AMAug 30
to mathja...@googlegroups.com
Your problem here is that you are loading the wrong TeX extension.  You want to load [tex]/html, not [tex]/texhtml.  The former is what defines \class, \style, and the other similar macros, while the latter allows you to include HTML tags within TeX expressions.

The reason this is important is because when the \let\oldclass=\class is performed the definition of \class is the one ceated by the autoload extension, and so it is a command that causes the [tex]/html extension to be loaded.  It is not the definition of \class that that extension eventually give it.  So your \oldclass is a macro that loads th [tex]/html extension and then tries to process the expression again.  When that extension is loaded, \class is redefined to perform its usual operation, but \oldclass stays as a macro that loads [tex]/html.  That means when \oldclass is used in \rowClassParts, it tries again to load [tex]/html, and since it is never redefined to be the actual \class command, it keeps doing so, which leads to the recursive call error that you are seeing.

If you load the correct extension, it works.

Davide


Davide Cervone

unread,
Aug 30, 2025, 1:04:00 PMAug 30
to mathja...@googlegroups.com
Will this code also work for Mathtip since it also has two arguments like \class?

Yes, you should be able to modify it to work with \mathtip.

Also is it possible to make one for \bbox?

That depends on what you are after.  The \class macro works by adding the class to the two sides of the alignment (what is on the left of the & and what is on its right) separately.  Doing that with \bbox would work, but you would get a separate box on each side, not one box around the whole row of the alignment, which is what I suspect you would prefer.

If that is the case, it can be done as shows below, but there is one caveat:  you need to provide the sum of any padding and border widths so that the macros can adjust for the spacing that those introduce.

        \let\oldbbox=\bbox
        \renewcommand{\bbox}[2][]{\bboxParts{#1}#2&&\endParts}
        \def\bboxParts#1#2&#3&#4\endParts{
          \checkEmpty#4{
            \rlap{\kernedBBox#1|.267em|\endBBox{\phantom{#2#3}}}
            #2&#3
          }{
            \kernedBBox#1|0px|\endBBox{#2}
          }
          \endCheck
        }
        \def\checkEmpty#1#2#3\endCheck{#2}
        \def\kernedBBox#1|#2|#3\endBBox{\kern-#2\oldbbox[#1]}

The line breaks are to make it more readable, but they aren't needed (though they also don't cause and harm).

You provide the site of the padding+border by putting it after a vertical bar within the brackets of the \bbox call, as in the example file below:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>\bbox test</title>
<script>
window.MathJax ={
  loader: {
    load: ['[tex]/bbox']
  },
  tex: {
    packages: {'[+]': ['bbox']},
  },
  startup: {
    ready: () => {
      MathJax.startup.defaultReady();
      MathJax.tex2mml(String.raw`
        \let\oldbbox=\bbox
        \renewcommand{\bbox}[2][]{\bboxParts{#1}#2&&\endParts}
        \def\bboxParts#1#2&#3&#4\endParts{
          \checkEmpty#4{
            \rlap{\kernedBBox#1|.267em|\endBBox{\phantom{#2#3}}}
            #2&#3
          }{
            \kernedBBox#1|0px|\endBBox{#2}
          }
          \endCheck
        }
        \def\checkEmpty#1#2#3\endCheck{#2}
        \def\kernedBBox#1|#2|#3\endBBox{\kern-#2\oldbbox[#1]}
      `);
    },
  }
};
</script>
</head>
<body>

\begin{align}
\bbox[5px, border: 2px solid blue|7px]{a&=b}\\
a &= b
\end{align}

\[\bbox[5px, border: 2px solid blue]{a=b}\]

</body>
</html>

it would be potentially possible to try to determine the border and padding sizes from the bracketed argument itself, but it would be difficult using these kinds of macros, as the format is too flexible.  For that, you would probably need to move to a javascript-based MathJax macro.  I'm not planning to do any more work on this, as I've already put enough time into this.  I've done so because I think others might be interested in the techniques used here to make decisions within MathJax macros even though it doesn't have an if-then structure to call on.  If you want to pursue the javascript-based or other additional macros, you could contract with me for the work to be done; we can discus that off list if so.  I will send one more message for the \underscore question.

Davide

Davide Cervone

unread,
Aug 30, 2025, 4:22:10 PMAug 30
to mathja...@googlegroups.com
Also in my previous message I asked if the same thing can be done for \underbrace{1&=1}_{1} and \underbrace{1=1}_{1}.

This is a bit tricker, as you don't have any control over what comes after the \underbrace, so it is difficult to test for the "_" from within MathJax's non-javascript macros.

Here is an example file that implements one approach:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>\underbrace test</title>
<script>
window.MathJax ={
  tex: {packages: {'[-]': ['textmacros']}},
  startup: {
    ready: () => {
      MathJax.startup.defaultReady();
      MathJax.tex2mml(String.raw`
        \let\oldunderbrace=\underbrace
        \renewcommand{\underbrace}[1]{\underbraceParts#1&&\endParts}
        \def\underbraceParts#1&#2&#3\endParts{
          \checkEmpty#3{
            \underbraceBox{#1}{#2}
          }{
            \oldunderbrace{#1}
          }\endCheck
        }
        \def\checkEmpty#1#2#3\endCheck{#2}
        \def\checkLength#1#2#3\multChars\multChars#4#5\endcheck{#4}
        \def\checkUnderscore#1_#2#3\endcheck{#2}
        \def\doUnderscore#1{\makeUnderbrace{_{\hskip-5em#1\hskip-5em}}}
        \def\underbraceBox#1#2#3{
          \def\makeUnderbrace##1{\rlap{\underbrace{\phantom{#1#2}}##1}#1&#2}
          \def\multChars{\makeUnderbrace{}{#3}}
          \checkLength#3\multChars\multChars\multChars{
            \checkUnderscore#3\doUnderscore_{\makeUnderbrace{}#3}\endcheck
          }\multChars\multChars{
            \makeUnderbrace{}{}
          }\endcheck
        }
        `);
    },
  }
};
</script>
</head>
<body>

\begin{align}
\underbrace{a&=b+c+d}\\
\underbrace{a&=b+c+d}_{xyz}\\
\underbrace{a&=b}_{xyz\,xyx\,xyz\,xyz}\\
a &= b
\end{align}

\[\underbrace{a=b+c+d}\]

\[\underbrace{a=b+c+d}_{xyz}\]

</body>
</html>

The two \hskip-5em are to reduce the size of the material under the brace in case it extends beyond the size of the stretched brace (as in the this line of the alignment above).  Without that, the brace would be shifted to the right.  This allows an overlap of 5em on each side before things get pushed out of place.  Adjust as needed.  Note that a side effect of this is that the overlap is not counted in the width of the table itself, but that seemed to be the lesser of two evils.

In the case that the table row is not very wide and one of the fixed-size versions of the brace is used, it may be slightly misplaced, as those are allowed to extend beyond the edges of the material covered by the brace, but that is not taken into account here (the macro can't make the needed measurements).  You can see this in the placement of the brace in the third row, which is slightly skewed to the right.

I hope these are enough for you to do what you need, as I will not be able to make any additional macros for you at this point.

Davide


Reply all
Reply to author
Forward
0 new messages