Integrating MermaidJS with ReactJS Hooks

2023-02-08

At devtoolsdaily.com, we recently added a MermaidJS playground (you can check it out here: https://devtoolsdaily.com/diagrams/mermaidjs/playground).

Instead of relying on existing packages such as react-mermaid or react-mermaid2, which had limited popularity based on their low GitHub stars and npm downloads, we opted to implement our own wrapper.

We also chose to load the dependencies via CDN links. This is our preferred method for loading external dependencies, as it allows us to only load specific packages when needed, rather than having a large number of packages installed for just one of our web tools.

To implement MermaidJS, we started with the following code

function MermaidWrapper({markup}) {    
    return <div className="mermaid">{markup}</div>;
}

We then used the use_script helper, which we commonly use for other tools, to load MermaidJS from the CDN

function new_script(src) {
    return new Promise(function(resolve, reject){
      if (typeof window !== "undefined") {
        var script = window.document.createElement('script');
        script.src = src;
        script.addEventListener('load', function () {
          resolve();
        });
        script.addEventListener('error', function (e) {
          reject(e);
        });
        window.document.body.appendChild(script);
      }
    })
  };

The first time the component is rendered, we load MermaidJS from the CDN

useEffect(() => {
    if (!window.mermaid) {
        var my_script = new_script('https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.3.0/mermaid.min.js');
        my_script.then(() => {
            window.mermaid.mermaidAPI.initialize({
                securityLevel: 'loose',
            });
            window.mermaid.contentLoaded();
        });
    }
}, [])

For live editing, we want to trigger a re-render every time the markup changes. To do this, we use another useEffect hook

useEffect(() => {
    if (window.mermaid) {
        document.getElementById('mermaidHolder').removeAttribute('data-processed');
        window.mermaid.contentLoaded();
    }
}, [markup])

Putting it all together, here's our final implementation of the MermaidJS wrapper, which loads MermaidJS from the CDN on start

function MermaidWrapper({markup}) {
    useEffect(() => {
        if (!window.mermaid) {
            var my_script = new_script('https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.3.0/mermaid.min.js');
            my_script.then(() => {
                window.mermaid.mermaidAPI.initialize({
                    securityLevel: 'loose',
                });
                window.mermaid.contentLoaded();
            });
        }
    }, [])

Please check out https://devtoolsdaily.com/ for other articles First version of a playground is available there https://devtoolsdaily.com/diagrams/mermaidjs/playground 

In a few days/weeks we plan to add:

  1. side by side comparison of mermaidJS and graphviz
  2. mermaidJS cheatsheet
  3. real-world examples of mermaidJS diagrams
  4. code examples on how to generate beautiful mermaidJS charts.