Using React in a Plain HTML File – No Build Tools

Run React directly in an HTML page with CDN scripts and Babel – modern createRoot syntax, JSX in the browser, and when to graduate to Vite.

Using React JS in HTML file

Last updated: July 2026 — uses the modern createRoot API

You don’t need Node, npm, or a bundler to try React. Three script tags in an HTML file are enough for learning, prototypes, or sprinkling one interactive widget into an existing site.

The complete file

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React in HTML</title>
  <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>

  <script type="text/babel">
    function Counter() {
      const [count, setCount] = React.useState(0);
      return (
        <div>
          <h2>Clicked {count} times</h2>
          <button onClick={() => setCount(count + 1)}>Click me</button>
        </div>
      );
    }

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<Counter />);
  </script>
</body>
</html>

Open it in a browser — a working React component with state, no installation.

The pieces, briefly

  • react / react-dom — the library and its DOM renderer, loaded as globals (ReactReactDOM).
  • @babel/standalone — compiles JSX in the browser, which is why the script tag is type="text/babel". Without it, JSX’s <Counter /> syntax is a JS error.
  • createRoot — the React 18+ mounting API. Older tutorials show ReactDOM.render(<App/>, el), which is deprecated; if you copy legacy snippets, swap them to the createRoot form above.

Skipping JSX entirely also works — React.createElement('button', {onClick}, 'Click me') — and drops the Babel dependency, at the cost of readability.

Honest limitations

In-browser Babel compiles on every page load, so this setup is not for production: it’s slower, ships megabytes of compiler, and can’t use npm packages or import. It’s a sandbox.

When you outgrow it

The moment you want multiple components in separate files or any npm library, create a real project — it takes one minute:

npm create vite@latest my-app -- --template react
cd my-app && npm install && npm run dev

Everything you wrote in the HTML file carries over unchanged — same components, same hooks — now with instant reload and production builds. And if your backend is Laravel, Breeze + Inertia sets React up inside Laravel directly..

Comments

comments