Fine-Grained Reactivity.
Zero Virtual DOM.

Signals bind directly to DOM nodes via WeakRef. Every update is O(1). No diffing, no reconciliation, no waste.

Get Started Try Playground
$ npm create cellui@latest
import { signal, computed, view, mount } from '@cmj/cellui'; const App = () => { const count = signal(0); const doubled = computed(() => count.value * 2); return view` <div> <h1>${count} × 2 = ${doubled}</h1> <button onclick="${() => count.value++}">+</button> </div> `; }; mount('#app', () => App());
~5KB
Gzipped runtime
O(1)
Update granularity
0
Dependencies
101
Tests passing

Why CellUI?

Direct Signal-to-DOM

No virtual DOM, no diffing. Signals update the exact text node or attribute that changed. Nothing else runs.

🧠

WeakRef Memory Safety

Subscriptions are tied to DOM nodes via WeakRef. When a node is garbage collected, the signal automatically unsubscribes.

🧬

Tagged Templates

No JSX, no build step required. Write HTML with signal interpolation using tagged template literals.

🧭

Built-in Router

URL-synced routing with pattern matching, params extraction, and browser history support.

🎭

Portals & Transitions

Render outside the parent tree for modals. CSS enter/leave transitions with automatic cleanup.

🧪

Testing Utilities

Built-in render() with getByText, getBySelector, and unmount. No external testing library needed.

Performance

CellUI vs equivalent vanilla JS implementations

Signal Updates (10K subscribers)0.5x — 2x faster
Effect Tracking (100 signals)0.7x — 1.4x faster
Fine-Grained vs VDOM Diffing0.02x — 49x faster
Text Node Updates (10K)1.3x overhead
List Reconciliation (1K shuffle)2.4x overhead

Ready to try it?

CellUI is open source under the ISC license.

Read the Docs View on GitHub