Skip to content

Instantly share code, notes, and snippets.

@mfdj
Last active May 20, 2026 21:13
Show Gist options
  • Select an option

  • Save mfdj/3616370815c49fe971970e6cdb79f7a3 to your computer and use it in GitHub Desktop.

Select an option

Save mfdj/3616370815c49fe971970e6cdb79f7a3 to your computer and use it in GitHub Desktop.

Goal

Using React JSX directly in native web platform source files (html, js) bypassing the need to build/compile.

Key references

https://peterkellner.net/2024/05/10/running-react-19-from-a-cdn-and-using-esm.sh/

  • got me going in a good direction but didn't have a JSX solution

https://blog.tripu.info/react-19/

  • unlocked the React 19 JSX puzzle trying to juggle ESM and Babel

Noteworthy but not the approach I wanted

Compiling TypeScript/TSX at the edge is interesting but is pure overhead for my use case

import { party } from "./party.js";
export function Message({ greeting, subject }) {
return <div className="message">{party(greeting, subject)}</div>;
}
export function party(...messages) {
return messages
.map((message) => `🎉 ${message}`)
.reduce((agg, next) => `${agg} ${next}`);
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React 18 no build (UMD)</title>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
</head>
<body>
<div id="react-root"></div>
<script type="text/babel">
async function main() {
const { party } = await import("./party.js");
// Attempting to import this component as JSX fails with `Unhandled Promise Rejection: TypeError: 'text/jsx' is not a valid JavaScript MIME type.`
// const { Message } = await import("./components.jsx");
function Message({ greeting, subject }) {
return <div className="message">{party(greeting, subject)}</div>;
}
const element = (
<div className="container">
<Message greeting="Hello" subject="World" />
<Message greeting="Goodbye" subject="World" />
</div>
);
ReactDOM.createRoot(document.getElementById("react-root")).render(
element,
);
}
main();
</script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React 19 no build (ESM, with hacks)</title>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19.2.0",
"react-dom/client": "https://esm.sh/react-dom@19.2.0/client"
}
}
</script>
<script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
</head>
<body>
<div id="react-root"></div>
<script type="module">
import React from "react";
import ReactDOM from "react-dom/client";
window.module_exports = { React, ReactDOM };
</script>
<script type="text/babel">
const { React, ReactDOM } = window.module_exports;
async function main() {
const { party } = await import("./party.js");
// Attempting to import this component as JSX fails with `Unhandled Promise Rejection: TypeError: 'text/jsx' is not a valid JavaScript MIME type.`
// const { Message } = await import("./components.jsx");
function Message({ greeting, subject }) {
return <div className="message">{party(greeting, subject)}</div>;
}
const element = (
<div className="container">
<Message greeting="Hello" subject="World" />
<Message greeting="Goodbye" subject="World" />
</div>
);
ReactDOM.createRoot(document.getElementById("react-root")).render(element);
}
main();
</script>
</body>
</html>
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
port=${1-3000}
php -S "localhost:$port" -t .
@tripu

tripu commented May 20, 2026

Copy link
Copy Markdown

I'm glad to know my post was useful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment