It's midnight and I'm waiting for a surgery on 01:00, and I've got exams to read for, but.. hacking things together is more fun.

Let's see if this works

^ This one doesn't work; Babel tags won't get called if script is appended later..

^ Works!

^ Try again for good measure (in case react conflicts, etc) >> Works!

Here's the working code


<div>
  <script>
    (function() {
      // Generate a unique ID for this instance's mount point.
      var instanceId = Math.random().toString(36).substr(2, 9);
      var mountId = "ghost-react-root-" + instanceId;

      // Get the container element (the parent of this <script> tag).
      var blockContainer = document.currentScript.parentElement;

      // Create and append a new <div> that will serve as the React mount point.
      var mountDiv = document.createElement("div");
      mountDiv.id = mountId;
      blockContainer.appendChild(mountDiv);

      // Helper to load an external script and return a Promise.
      function loadScript(url) {
        return new Promise(function(resolve, reject) {
          var script = document.createElement("script");
          script.src = url;
          script.onload = resolve;
          script.onerror = reject;
          document.head.appendChild(script);
        });
      }

      // If React, ReactDOM, and Babel haven't been loaded yet, load them once and store a global promise.
      if (!window.__ghostReactPromise) {
        window.__ghostReactPromise = (function() {
          var promises = [];
          if (!window.React) {
            promises.push(loadScript("https://unpkg.com/react@17/umd/react.development.js"));
          }
          if (!window.ReactDOM) {
            promises.push(loadScript("https://unpkg.com/react-dom@17/umd/react-dom.development.js"));
          }
          if (!window.Babel) {
            promises.push(loadScript("https://unpkg.com/@babel/standalone/babel.min.js"));
          }
          return Promise.all(promises);
        })();
      }

      // Once everything is loaded, compile and inject the React code.
      window.__ghostReactPromise.then(function() {
        // Replace this entire string with your JSX-based React code:
        var jsxCode = `
          class GhostCustomComponent extends React.Component {
            render() {
              return (
                <div>
                  <h1>Hello from your custom React component!</h1>
                  <p>Edit this JSX to build your own UI.</p>
                </div>
              );
            }
          }

          ReactDOM.render(<GhostCustomComponent />, document.getElementById('${mountId}'));
        `;

        // 1) Use Babel.transform to compile the JSX into plain JavaScript
        var transformed = Babel.transform(jsxCode, {
          presets: ["env", "react"]  // You can adjust these presets if needed
        }).code;

        // 2) Create a normal <script> tag with the compiled code and inject it
        var compiledScript = document.createElement("script");
        compiledScript.text = transformed;
        document.body.appendChild(compiledScript);
      }).catch(function(error) {
        console.error("Error loading React libraries:", error);
      });
    })();
  </script>
</div>

And for good measure, play around with some hooks stuff

Source


<div>
  <script>
    (function() {
      // Generate a unique ID for this instance's mount point.
      var instanceId = Math.random().toString(36).substr(2, 9);
      var mountId = "ghost-react-root-" + instanceId;

      // Get the container element (the parent of this <script> tag).
      var blockContainer = document.currentScript.parentElement;

      // Create and append a new <div> that will serve as the React mount point.
      var mountDiv = document.createElement("div");
      mountDiv.id = mountId;
      blockContainer.appendChild(mountDiv);

      // Helper to load an external script and return a Promise.
      function loadScript(url) {
        return new Promise(function(resolve, reject) {
          var script = document.createElement("script");
          script.src = url;
          script.onload = resolve;
          script.onerror = reject;
          document.head.appendChild(script);
        });
      }

      // If React, ReactDOM, and Babel haven't been loaded yet, load them once and store a global promise.
      if (!window.__ghostReactPromise) {
        window.__ghostReactPromise = (function() {
          var promises = [];
          if (!window.React) {
            promises.push(loadScript("https://unpkg.com/react@17/umd/react.development.js"));
          }
          if (!window.ReactDOM) {
            promises.push(loadScript("https://unpkg.com/react-dom@17/umd/react-dom.development.js"));
          }
          if (!window.Babel) {
            promises.push(loadScript("https://unpkg.com/@babel/standalone/babel.min.js"));
          }
          return Promise.all(promises);
        })();
      }

      // Once everything is loaded, compile and inject the React code.
      window.__ghostReactPromise.then(function() {
        // Replace this entire string with your JSX-based React code:
        var jsxCode = `
          function Calculator() {
            const [num1, setNum1] = React.useState("");
            const [num2, setNum2] = React.useState("");
            const [operation, setOperation] = React.useState("+");
            const [result, setResult] = React.useState(null);

            function calculate() {
              const n1 = parseFloat(num1);
              const n2 = parseFloat(num2);
              if (isNaN(n1) || isNaN(n2)) {
                setResult("Please enter valid numbers!");
                return;
              }

              let res;
              switch (operation) {
                case "+":
                  res = n1 + n2;
                  break;
                case "-":
                  res = n1 - n2;
                  break;
                case "*":
                  res = n1 * n2;
                  break;
                case "/":
                  res = n2 === 0 ? "Cannot divide by zero!" : n1 / n2;
                  break;
                default:
                  res = "Unknown operation";
              }
              setResult(res);
            }

            return (
              <div style={{ border: "1px solid #ccc", padding: "1em", width: "250px" }}>
                <h2>Simple React Calculator</h2>
                <div style={{ marginBottom: "0.5em" }}>
                  <label>Number 1: </label>
                  <input
                    type="text"
                    value={num1}
                    onChange={e => setNum1(e.target.value)}
                    style={{ marginLeft: "0.5em" }}
                  />
                </div>
                <div style={{ marginBottom: "0.5em" }}>
                  <label>Number 2: </label>
                  <input
                    type="text"
                    value={num2}
                    onChange={e => setNum2(e.target.value)}
                    style={{ marginLeft: "0.5em" }}
                  />
                </div>
                <div style={{ marginBottom: "0.5em" }}>
                  <label>Operation: </label>
                  <select
                    value={operation}
                    onChange={e => setOperation(e.target.value)}
                    style={{ marginLeft: "0.5em" }}
                  >
                    <option value="+">+</option>
                    <option value="-">-</option>
                    <option value="*">*</option>
                    <option value="/">/</option>
                  </select>
                </div>
                <button onClick={calculate}>Calculate</button>
                <div style={{ marginTop: "1em" }}>
                  <strong>Result: </strong>
                  <span>{result !== null ? result : "N/A"}</span>
                </div>
              </div>
            );
          }
          ReactDOM.render(<Calculator />, document.getElementById('${mountId}'));
        `;

        // 1) Use Babel.transform to compile the JSX into plain JavaScript
        var transformed = Babel.transform(jsxCode, {
          presets: ["env", "react"]  // You can adjust these presets if needed
        }).code;

        // 2) Create a normal <script> tag with the compiled code and inject it
        var compiledScript = document.createElement("script");
        compiledScript.text = transformed;
        document.body.appendChild(compiledScript);
      }).catch(function(error) {
        console.error("Error loading React libraries:", error);
      });
    })();
  </script>
</div>

V0.Dev

DeepSeek

Testing JSX inside Ghost