React without the React Tax β’ Accelerate React applications to SolidJS speeds without changing a single line of code
Reactless is a build-time compiler that detects static subtrees in your React components and replaces them with pre-compiled, optimized native DOM templates. It eliminates Virtual DOM overhead for static content, reducing React's reconciliation cost to near-zero.
The Promise: Massive performance boosts. Zero API changes. Zero migration. Zero rewrites. Keep your React ecosystem, ditch the performance overhead.
- π The Problem: The "React Tax"
- π‘ The Solution: Reactless
- π§ How It Works: Deep Dive
- π Performance Architecture
- βοΈ Competitive Analysis
- π Integration & Usage
- π§© Advanced Capabilities
- π― Why This Matters Now
- π Getting Started
React revolutionized frontend development with its component model and declarative approach, but this power comes at a cost. Even in mostly static components, React pays what we call "The React Tax":
// This seemingly simple component creates significant overhead
function StaticCard() {
return (
<div className="card">
<header className="card-header">
<h2>Welcome</h2> {/* Static - but still creates VDOM */}
</header>
<div className="card-body">
<p>Static content</p> {/* Static - but still creates VDOM */}
<p>More static content</p>{/* Static - but still creates VDOM */}
</div>
</div>
);
}Every render, React performs these expensive operations:
- Creates Virtual DOM objects for every node (even static ones)
- Traverses and diffs the entire tree structure
- Re-creates closures and event handlers
- Triggers garbage collection for the old VDOM nodes
The React Compiler (Forget) helps with memoization (step 3), but doesn't solve the fundamental VDOM overhead of steps 1, 2, and 4.
Reactless sits in your build pipeline and performs Selective Static Extraction. It treats React as the logic layer and leverages the browser's native DOM capabilities as the rendering layer, bypassing the VDOM entirely for content that doesn't change.
How it transforms your application:
// BEFORE: Standard React (VDOM overhead)
function ProductCard({ product }) {
return (
<div className="product-card bg-white rounded-lg shadow-md">
{/* β οΈ All these static elements create VDOM objects every render */}
<div className="product-image-container">
<div className="badge">New</div>
<img src={product.image} alt={product.name} />
</div>
<div className="product-content p-4">
<h3 className="product-title text-lg font-semibold">{product.name}</h3>
<p className="product-description text-gray-600">{product.description}</p>
<div className="product-footer flex justify-between items-center">
<span className="price text-xl font-bold">${product.price}</span>
<button className="add-to-cart-btn bg-blue-500 text-white px-4 py-2 rounded">
Add to Cart
</button>
</div>
</div>
</div>
);
}
// AFTER: Reactless optimized (Zero VDOM for static content)
function ProductCard({ product }) {
return (
<div className="product-card bg-white rounded-lg shadow-md">
{/* π― Static structure compiled to direct DOM template */}
<div className="product-image-container">
<div className="badge">New</div>
<img src={product.image} alt={product.name} />
</div>
<div className="product-content p-4">
{/* π― Only dynamic values need React intervention */}
<h3 className="product-title text-lg font-semibold">{product.name}</h3>
<p className="product-description text-gray-600">{product.description}</p>
<div className="product-footer flex justify-between items-center">
<span className="price text-xl font-bold">${product.price}</span>
{/* π― Static button structure, dynamic event handler */}
<button className="add-to-cart-btn bg-blue-500 text-white px-4 py-2 rounded">
Add to Cart
</button>
</div>
</div>
</div>
);
}Reactless is not a runtime library; it's a compiler with a tiny (<1KB) integration layer that works alongside React.
The Reactless Babel/SWC plugin performs sophisticated static analysis on your JSX, identifying "islands of stability":
- Static Structure: Elements whose position and hierarchy never change
- Static Attributes:
className,id,data-*, ARIA labels that are constant - Dynamic Holes: Precise identification of where dynamic data needs injection
Safety First: If a component contains complex patterns (dynamic spreads, indeterminate logic), Reactless automatically bails out and falls back to standard React rendering.
Reactless compiles static HTML into efficient template literals, similar to how SolidJS or Svelte works.
Input (Your React Component):
function UserProfile({ user, onEdit }) {
return (
<div className="profile-card">
<div className="profile-header">
<h2 className="text-2xl font-bold">{user.name}</h2>
<span className="badge">{user.role}</span>
</div>
<div className="profile-body">
<p className="email">{user.email}</p>
<p className="bio">{user.bio}</p>
</div>
<div className="profile-actions">
<button onClick={onEdit} className="btn btn-primary">
Edit Profile
</button>
</div>
</div>
);
}Output (Compiled & Optimized):
// Pre-compiled static template
const _template = document.createElement("template");
_template.innerHTML = `
<div class="profile-card">
<div class="profile-header">
<h2 class="text-2xl font-bold"></h2>
<span class="badge"></span>
</div>
<div class="profile-body">
<p class="email"></p>
<p class="bio"></p>
</div>
<div class="profile-actions">
<button class="btn btn-primary">Edit Profile</button>
</div>
</div>
`;
function UserProfile({ user, onEdit }) {
// Clone the pre-compiled template (O(1) operation)
const domRoot = _template.content.cloneNode(true);
// Direct DOM updates - no VDOM, no diffing
domRoot.querySelector('.profile-header h2').textContent = user.name;
domRoot.querySelector('.badge').textContent = user.role;
domRoot.querySelector('.email').textContent = user.email;
domRoot.querySelector('.bio').textContent = user.bio;
// Bridge React events to native DOM
return (
<ReactlessNode
dom={domRoot}
events={{
'button.btn-primary': { click: onEdit }
}}
/>
);
}This lightweight component (<1KB) seamlessly integrates pre-compiled DOM with React:
- Ref-based Injection: Wraps the DOM template in a React component that references the container
- Event Delegation: Bridges React's Synthetic Events to native DOM listeners, ensuring full compatibility with event propagation and React's event system
- Hydration Safety: For SSR, Reactless outputs standard HTML. On client hydration, it performs checksum matching and "claims" existing DOM nodes, skipping React's hydration for static subtrees
| Metric | Standard React | React + Reactless | Improvement |
|---|---|---|---|
| Initial Render | O(n) VDOM node creation | O(1) template clone + O(d) DOM updates | 5x - 20x faster |
| Re-renders | Full tree reconciliation | Direct DOM property updates | 10x - 100x faster |
| Memory Usage | High (Fiber nodes + VDOM) | Low (Native DOM only) | 60-80% reduction |
| Bundle Impact | Base React size | +0.8-1.2KB runtime | Negligible |
| SSR Performance | Full component render | HTML string concatenation | 2x - 5x faster |
Real-world impact:
- Landing pages: 60-90% static β 3-5x faster Time to Interactive
- E-commerce product listings: 4-8x faster re-renders when filtering
- Dashboard applications: 2-4x reduced memory usage
| Aspect | React Compiler | Reactless |
|---|---|---|
| Primary Goal | Prevent unnecessary re-renders | Eliminate rendering cost |
| Optimization | Memoization, conditional skip | VDOM bypass, direct DOM |
| Scope | When components run | How components render |
| Verdict | Perfect together - Use React Compiler to stabilize your component graph, and Reactless to accelerate rendering |
| Aspect | Million.js | Reactless |
|---|---|---|
| Adoption | Manual block() wrappers |
Fully automatic |
| Safety | Developer responsibility | Compiler-verified |
| Integration | Opt-in per component | Zero-config |
| Approach | Virtual DOM alternative | DOM template compilation |
| Aspect | Alternative Frameworks | Reactless |
|---|---|---|
| Learning Curve | New framework, new mental model | Zero learning |
| Ecosystem | Lose React libraries | Keep everything |
| Migration | Full rewrite required | Drop-in upgrade |
| Team Impact | Retraining needed | Instant adoption |
The Reactless Advantage: You get next-generation performance while keeping your entire React investmentβcomponents, libraries, tools, and team expertise.
Reactless is designed as a "drop-in" solution for most React projects.
# npm
npm install reactless --save-dev
# yarn
yarn add reactless --dev
# pnpm
pnpm add reactless -DVite:
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import reactless from "reactless/vite";
export default defineConfig({
plugins: [
reactless(),
react()
]
});Next.js:
// next.config.js
const withReactless = require('reactless/next')();
module.exports = withReactless({
// Your Next.js config
});Webpack:
// webpack.config.js
const ReactlessPlugin = require('reactless/webpack');
module.exports = {
// ... your config
plugins: [
new ReactlessPlugin()
]
};Reactless is aggressive by default but respects your boundaries.
Opt-out for specific components:
/** @reactless off */
function ComplexInteractiveChart() {
// Reactless will skip optimization for this component
return <svg>...</svg>;
}Force optimization with validation:
/** @reactless force */
function CriticalPerformanceComponent() {
// Reactless will optimize and warn if any patterns prevent optimization
return <div>...</div>;
}Debug mode:
/** @reactless debug */
function ComponentUnderAnalysis() {
// Build outputs detailed optimization report
return <div>...</div>;
}Reactless seamlessly integrates with Next.js App Router and React Server Components:
// app/products/page.js - Server Component
async function ProductPage({ params }) {
const products = await fetchProducts();
return (
<div className="products-page">
<SearchBar /> {/* Client Component */}
<ProductGrid products={products}>
{/* π― Server-side: Compiled to efficient HTML strings */}
{/* π― Client-side: Zero hydration cost for static structure */}
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</ProductGrid>
</div>
);
}Benefits:
- Server: Reduced CPU usage through HTML template concatenation
- Client: Instant hydration by claiming existing DOM nodes
- Streaming: Progressive enhancement with static structure first
Reactless optimizes what it can, even in complex components:
function MixedComponent({ user, dynamicContent, items }) {
return (
<div className="container">
{/* β
Fully static - becomes DOM template */}
<header className="page-header">
<h1>Application Title</h1>
<nav className="main-nav">...</nav>
</header>
{/* β
Static wrapper, dynamic content */}
<main className="content">
<UserProfile user={user} /> {/* Partially optimized */}
<DynamicFeed data={dynamicContent} /> {/* React handled */}
</main>
{/* β
Static list structure, dynamic items */}
<ul className="item-list">
{items.map(item => (
<li key={item.id} className="item">
{/* Static structure around dynamic data */}
<span className="item-icon">π¦</span>
<span className="item-name">{item.name}</span>
<span className="item-price">${item.price}</span>
</li>
))}
</ul>
{/* β
Fully static - becomes DOM template */}
<footer className="page-footer">
<p>Copyright 2024</p>
<div className="links">...</div>
</footer>
</div>
);
}Reactless detects and optimizes predictable patterns:
// BEFORE: Runtime map operation
function ColorPalette() {
const colors = ['red', 'blue', 'green', 'yellow'];
return (
<div className="color-palette">
{colors.map(color => (
<div
key={color}
className={`color-swatch ${color}`}
style={{ backgroundColor: color }}
/>
))}
</div>
);
}
// AFTER: Compile-time unrolling
// Generated template contains all four swatches statically
// Zero runtime iteration costWe're in the "Compiler Era" of frontend development, and the rules have changed:
- Svelte proved that compile-time optimization beats runtime abstraction
- React proved that component-driven development wins for DX and scalability
- SolidJS proved that fine-grained reactivity can deliver incredible performance
Reactless unifies these insights.
It brings Svelte-level performance to the React ecosystem, enabling teams to:
- Scale existing applications without costly rewrites
- Achieve startup-level performance in enterprise codebases
- Adopt incrementally with zero team retraining
- Leverage the entire React ecosystem while getting next-gen performance
Ready to accelerate your React application?
# 1. Install Reactless
npm install reactless --save-dev
# 2. Add to your build config
# (See integration examples above)
# 3. Build and experience the speed!
npm run buildMigration Strategy:
- Start with your most static components (headers, footers, cards)
- Progress to complex layouts with mixed static/dynamic content
- Use debug mode to identify optimization opportunities
- Measure performance gains with each iteration
MIT Β© 2025 Reactless Contributors
Reactless: Keep your React. Lose the overhead. π