Reactolith hydrates HTML into React. Any tag with a hyphen becomes a React component. Everything else stays plain DOM. Works with any backend that returns HTML — or no backend at all.
Your backend renders HTML. Reactolith picks up any tag with a hyphen and renders it through React. Navigation, forms and SSE updates all use the same path: HTML in, React reconciler out.
Return HTML from your existing controllers. Tags like
<my-button>
become React components. The rest is plain DOM.
The built-in router fetches the next page and lets React reconcile against the live tree. Component state, focus and scroll stay where they were.
Mercure SSE pushes HTML updates through the same render pipeline. The DOM updates, React state stays.
The HTML on the left is whatever your backend already renders. The TSX on the right maps tag names to React components.
Any tag with a hyphen → React component. Everything else → native DOM. How it works →
Any backend, no backend, or a static file on a CDN.
Path helpers, permission checks, locale switches keep working.
Navigate between pages, React state stays.
Server can add or remove fields without losing focus.
Small runtime, no compiler step required.
Mercure SSE pushes HTML through the same render path.
Back-button behaves like a regular browser.
Generate web-types for JetBrains and VS Code.
| reactolith | Inertia.js | htmx | Hotwire / Turbo | Full SPA | |
|---|---|---|---|---|---|
| Returns HTML from backend | ● | ○ | ● | ● | ○ |
| Real React components | ● | ● | ○ | ○ | ● |
| State across navigation | ● | ◐ | ○ | ◐ | ● |
| Reuses backend helpers | ● | ○ | ● | ● | ○ |
| Build step required | no | yes | no | small | yes |
| Replaces your router | no | yes | no | yes | yes |
More detail in the comparisons section.
One npm install,
a few lines of glue, and your backend can render React.