Skip to content

React & JSX ​

React works out of the box. Vantris understands JSX natively and uses the automatic JSX runtime by default, so you don't need to import React. For stateful Fast Refresh — edits that update a component in place without losing its state — add the official @vantris/react plugin.

Zero-config JSX ​

Install the runtime packages and point your entry at a .tsx file:

bash
npm install react react-dom
tsx
// src/main.tsx
import { createRoot } from "react-dom/client";

function App() {
  return <h1>Hello Vantris</h1>;
}

createRoot(document.getElementById("app")!).render(<App />);
html
<!-- index.html -->
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>

That's a complete React app — no Babel config, no import React from "react".

Choosing the JSX runtime ​

The runtime is selected by your tsconfig.json:

tsconfig jsxRuntimeimport React?
"react-jsx"automaticnot needed
"react"classicrequired

For non-React JSX libraries (Preact, Emotion), set jsxImportSource:

jsonc
// tsconfig.json — Preact
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}

Fast Refresh with @vantris/react ​

Native JSX gets you rendering, but a plain edit re-runs the whole module and resets component state. The @vantris/react plugin adds React Fast Refresh: a save updates the component in place and keeps its state (form inputs, counters, open/closed panels).

bash
npm install -D @vantris/react
ts
// vantris.config.ts
import { defineConfig } from "vantris";

export default defineConfig({
  plugins: ["@vantris/react"],
});

That's it. vantris dev now has Fast Refresh; vantris build compiles JSX as usual (the plugin steps aside in a build).

Plugins are referenced by string

Vantris loads plugins by string — a package name or a local path. To pass options, wrap the plugin in a tiny local module and reference that file instead. See With options.

What the plugin adds ​

  • Fast Refresh — component edits update in place, preserving state, over Vantris's HMR channel (dev only).
  • JSX via Babel — compiled with the automatic runtime by default; switch to classic or a custom jsxImportSource through the plugin's options.
  • Pre-bundling — seeds optimizeDeps.include with react, react-dom, react-dom/client, and the JSX runtimes, so the dev server is warm before the first request.

In a production build the plugin defers JSX compilation to Vantris/Rolldown and does nothing else.

The full option table, the "with options" wrapper pattern, and how each hook works are on the @vantris/react page.

Using HMR in a React app ​

With @vantris/react installed, individual components refresh automatically — you rarely touch import.meta.hot directly. When you need custom teardown for non-component modules (stores, singletons), the HMR API is still available and behaves the same as in any Vantris app.

Type declarations ​

Install the React types for editor support and your typecheck script:

bash
npm install -D @types/react @types/react-dom

And add vantris/client to tsconfig.json types for import.meta.env, import.meta.hot, and asset imports. See TypeScript and Client Types.

A complete minimal example ​

jsonc
// package.json
{
  "type": "module",
  "scripts": {
    "dev": "vantris dev",
    "build": "vantris build",
    "preview": "vantris preview"
  },
  "dependencies": { "react": "^19", "react-dom": "^19" },
  "devDependencies": {
    "vantris": "^1.2.0",
    "@vantris/react": "^0.1.0",
    "@types/react": "^19",
    "@types/react-dom": "^19"
  }
}
ts
// vantris.config.ts
import { defineConfig } from "vantris";
export default defineConfig({ plugins: ["@vantris/react"] });
tsx
// src/main.tsx
import { createRoot } from "react-dom/client";
import { App } from "./App";
createRoot(document.getElementById("app")!).render(<App />);
tsx
// src/App.tsx — edit this while the counter is non-zero; the count survives
import { useState } from "react";

export function App() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>Count: {n}</button>;
}

Released under the MIT License.