Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering Math in React Component

I am trying to Render Math Equation in a React Component with MathJax. It actually worked well if I pre-render it within the HTML file, but it is a mess when i try rendering it in React.

Here's my code

class Latex extends React.Component {

constructor(props) {
    super(props);
}

componentDidMount(){
    MathJax.Hub.Queue(['Typeset', MathJax.Hub, ReactDOM.findDOMNode(this)]);
}

componentDidUpdate() {
    MathJax.Hub.Queue(['Typeset', MathJax.Hub, ReactDOM.findDOMNode(this)]);
}

render() {
    //dangerouslySetInnerHTML={{__html: this.props.children}}
    return (
         <h5 dangerouslySetInnerHTML={{__html: this.props.children}}></h5>
    );
}
}

Math Display both in Regular HTML and React Element

like image 685
Ionware Avatar asked Aug 14 '26 14:08

Ionware


2 Answers

I used a combination of algebra.js and react-mathjax libraries to get it working in ES6. Because all these other packages are poorly maintained. For react-mathjax please use this repo.

Here's an example for showing fractions:

import React from 'react';
import { Fraction, toTex } from 'algebra.js';
import { Node, Context } from 'react-mathjax';

function Formula(props) {
  return (
    <Context input="tex">
      <Node inline>{props.tex}</Node>
    </Context>
  );
}

export default function FractionDisplay() {
  const a = new Fraction(1, 5);
  const b = new Fraction(2, 7);
  const answer = a.multiply(b);

  const question = <Formula tex={`${toTex(a)} × ${toTex(b)} = ${toTex(answer)}`} />;

  return (
    <div>
      {question}
    </div>
  );
}
like image 72
Ansjovis86 Avatar answered Aug 17 '26 04:08

Ansjovis86


Been a couple years, but if anyone is looking for a functional + mathjax3 based approach there is this repo:

https://github.com/jpribyl/react-hook-mathjax

demo of it is available at https://johnpribyl.com/react-hook-mathjax/

Usage is like this:

Basic inline display

import React from "react";
import Tex2SVG from "react-hook-mathjax";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Tex2SVG display="inline" latex="e^{i \pi} + 1 = 0" />
      </header>
    </div>
  );
}

export default App;

Customizing MathJax options

import React from "react";
import Tex2SVG, { MathJaxProvider } from "react-hook-mathjax";

// This object contains the default options, more info at:
// http://docs.mathjax.org/en/latest/options/output/svg.html 
const mathJaxOptions = {
  svg: {
    scale: 1,                      // global scaling factor for all expressions
    minScale: .5,                  // smallest scaling factor to use
    mtextInheritFont: false,       // true to make mtext elements use surrounding font
    merrorInheritFont: true,       // true to make merror text use surrounding font
    mathmlSpacing: false,          // true for MathML spacing rules, false for TeX rules
    skipAttributes: {},            // RFDa and other attributes NOT to copy to the output
    exFactor: .5,                  // default size of ex in em units
    displayAlign: 'center',        // default for indentalign when set to 'auto'
    displayIndent: '0',            // default for indentshift when set to 'auto'
    fontCache: 'local',            // or 'global' or 'none'
    localID: null,                 // ID to use for local font cache (for single equation processing)
    internalSpeechTitles: true,    // insert <title> tags with speech content
    titleID: 0                     // initial id number to use for aria-labeledby titles
  }
}

function App() {
  return (
    <div>
      <MathJaxProvider options={mathJaxOptions} />
      <div className="App">
        <header className="App-header">
          <Tex2SVG display="inline" latex="e^{i \pi} + 1 = 0" />
        </header>
      </div>
    </div>
  );
}

export default App;

Parsing user input

import React from "react";
import Tex2SVG from "react-hook-mathjax";

function App() {
  const [inputValue, setInputValue] = React.useState(
    "G_{\\mu\\nu} + \\Lambda g_{\\mu\\nu} = \\kappa T_{\\mu\\nu}",
  );

  return (
    <div className="App">
      <header className="App-header">
        <h3>React Hook MathJax</h3>
        <input
          type="text"
          defaultValue={inputValue}
          onChange={e => setInputValue(e.target.value)}
        />

        <div className="tex-container">
          <Tex2SVG class="tex" tabindex={-1} latex={inputValue} />
        </div>
      </header>
    </div>
  );
}

export default App;

Handling error states

import React from "react";
import Tex2SVG from "react-hook-mathjax";

const getErrorFromHTML = (html) =>
  html.children[1].firstChild.firstChild.attributes["data-mjx-error"].value;

function App() {
  const [inputValue, setInputValue] = React.useState(
    "G_{\\mu\\nu} + \\Lambda g_{\\mu\\nu} = \\kappa T_{\\mu\\nu}",
  );
  const [lastValidInput, setLastValidInput] = React.useState("");
  const [error, setError] = React.useState(null);
  const hasError = error !== null;

  return (
    <div className="App">
      <header className="App-header">
        <h3>React Hook MathJax</h3>
        <input
          className={`${hasError ? "error" : ""}`}
          type="text"
          defaultValue={inputValue}
          onChange={e => {
            setInputValue(e.target.value);
            setError(null);
          }}
        />

        <div className="tex-container">
          <Tex2SVG
            class="tex"
            tabindex={-1}
            latex={hasError ? lastValidInput : inputValue}
            onSuccess={() =>
              setLastValidInput(hasError ? lastValidInput : inputValue)
            }
            onError={html => setError(getErrorFromHTML(html))}
          />
        </div>
    {hasError && <div>hint: {error}</div>}
      </header>
    </div>
  );
}

export default App;

API

MathJaxProvider props:

options Object, optional

  • Sets MathJax configuration.
  • Default: Official MathJax configuration

Tex2SVG props:

latex string, required

  • The string which is passed to MathJax for conversion. Must be valid ![LaTeX](https://upload.wikimedia.org/wikipedia/commons/thumb/9/92/LaTeX_logo.svg/800px-LaTeX_logo.svg.png =50x) in order for a successful conversion into an svg
  • Default: ''

onSuccess (HTMLElement) => void, optional

  • Triggered after a successful conversion of LaTeX string into an svg - it receives the html object generated by MathJax
  • Default: (html: HTMLElement) => {}

onError (HTMLElement) => void, optional

  • Triggered after a failed conversion of LaTeX string into an svg - it receives the html object generated by MathJax
  • Default: (html: HTMLElement) => {}

Other html attributes {[key: string]: any} optional

  • All other props passed into this component will be directly translated onto the DOM node
  • This allows you to add css classes or other handlers, see usage examples above
  • NOTE: this does not attach to the virtual DOM, so pass class - not className etc
like image 45
kibble Avatar answered Aug 17 '26 05:08

kibble