React & Frameworks
Based Page supports React and other modern frameworks with no build step. Import them directly from esm.sh in a <script type="module"> tag and deploy a single HTML file.
React via esm.sh
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My React App</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-950 text-white min-h-screen">
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react@18'
import { createRoot } from 'https://esm.sh/react-dom@18/client'
function Counter() {
const [count, setCount] = useState(0)
return React.createElement('div', { className: 'p-8' },
React.createElement('h1', { className: 'text-2xl font-bold mb-4' }, `Count: ${count}`),
React.createElement('button', {
className: 'px-4 py-2 bg-blue-600 rounded',
onClick: () => setCount(c => c + 1)
}, 'Increment')
)
}
createRoot(document.getElementById('root')).render(React.createElement(Counter))
</script>
</body>
</html>Deploy it:
"Deploy this React counter app at the slug 'react-counter'."
Deployed successfully!
URL: https://react-counter.based.pageJSX Without a Build Step
esm.sh supports HTM — a tagged template literal JSX alternative that works without a transpiler:
<script type="module">
import { h, render } from 'https://esm.sh/preact@10'
import { useState } from 'https://esm.sh/preact@10/hooks'
import htm from 'https://esm.sh/htm@3'
const html = htm.bind(h)
function App() {
const [count, setCount] = useState(0)
return html`
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Count: ${count}</h1>
<button class="px-4 py-2 bg-blue-600 rounded" onClick=${() => setCount(c => c + 1)}>
Increment
</button>
</div>
`
}
render(html`<${App} />`, document.body)
</script>Preact (Lighter Alternative)
Preact is a 3KB React-compatible alternative. It works identically but loads faster:
<script type="module">
import { h, render } from 'https://esm.sh/preact@10'
import { useState, useEffect } from 'https://esm.sh/preact@10/hooks'
function App() {
const [data, setData] = useState(null)
useEffect(() => {
fetch('https://api.example.com/data')
.then(r => r.json())
.then(setData)
}, [])
return h('div', { class: 'p-8' },
data ? h('pre', null, JSON.stringify(data, null, 2)) : h('p', null, 'Loading...')
)
}
render(h(App, null), document.getElementById('root'))
</script>SPA Routing with React Router
For apps with client-side routing, enable is_spa: true when deploying. This makes all 404 requests fall back to index.html, allowing React Router to handle the path.
For a single-file React app with routing:
<script type="module">
import React from 'https://esm.sh/react@18'
import { createRoot } from 'https://esm.sh/react-dom@18/client'
import { BrowserRouter, Routes, Route, Link } from 'https://esm.sh/react-router-dom@6'
function Home() {
return React.createElement('div', null, 'Home page')
}
function About() {
return React.createElement('div', null, 'About page')
}
function App() {
return React.createElement(BrowserRouter, null,
React.createElement('nav', null,
React.createElement(Link, { to: '/' }, 'Home'),
' | ',
React.createElement(Link, { to: '/about' }, 'About')
),
React.createElement(Routes, null,
React.createElement(Route, { path: '/', element: React.createElement(Home) }),
React.createElement(Route, { path: '/about', element: React.createElement(About) })
)
)
}
createRoot(document.getElementById('root')).render(React.createElement(App))
</script>Tell Claude to deploy with is_spa: true:
"Deploy this React Router app at 'my-spa'. Enable SPA mode for client-side routing."
Multi-file React App
If you have a pre-built React app (from vite build or create-react-app), use the multi-file deploy format:
deploy called with:
files: [
{ path: "index.html", contentType: "text/html", content: "..." },
{ path: "assets/index.js", contentType: "application/javascript", content: "..." },
{ path: "assets/index.css", contentType: "text/css", content: "..." }
]
is_spa: trueUseful esm.sh Packages
| Package | Import |
|---|---|
| React 18 | https://esm.sh/react@18 |
| ReactDOM | https://esm.sh/react-dom@18/client |
| Preact | https://esm.sh/preact@10 |
| Preact hooks | https://esm.sh/preact@10/hooks |
| HTM | https://esm.sh/htm@3 |
| React Router | https://esm.sh/react-router-dom@6 |
| Zustand | https://esm.sh/zustand@4 |
| date-fns | https://esm.sh/date-fns@3 |
| Zod | https://esm.sh/zod@3 |
| framer-motion | https://esm.sh/framer-motion@11 |
Notes
- No Node.js, no
npm install, no bundler — everything runs in the browser. - esm.sh automatically resolves dependencies, so
react-domimportingreactjust works. - For local development before deploying, any static HTTP server works (e.g.
npx serve). is_spa: trueis only needed for apps with client-side routing (React Router, etc.). Single-page apps without routing don't need it.