Back

Ripple: A New TypeScript UI Framework to Watch

Ripple: A New TypeScript UI Framework to Watch

If you’ve spent time wrestling with React’s useMemo, useCallback, and stale closure bugs, you already know the mental overhead that comes with managing reactivity manually. Ripple, a new TypeScript framework created by Dominic Gannaway (React Hooks contributor, Inferno author, Svelte 5 core maintainer), takes a different approach entirely: compile the reactivity away, and let the framework handle the rest.

Here’s what makes it technically interesting.

Key Takeaways

  • Ripple is a compiler-driven UI framework that uses .ripple files and generates fine-grained DOM update logic — no virtual DOM or reconciliation required.
  • Its reactivity model centers on track() and the @ access operator, eliminating the need for dependency arrays, useMemo, or useCallback.
  • Reactive collections (#[] and #{}) allow direct mutation that automatically triggers UI updates.
  • The framework offers solid developer tooling (Vite integration, VSCode extension, scoped styles), but remains an early-stage experiment — worth studying, not yet ready for production.

What Is the Ripple UI Framework?

Ripple is a compiler-driven UI framework built around .ripple files — its own module format, distinct from .tsx or .jsx. Rather than shipping a virtual DOM and diffing algorithm at runtime, Ripple’s compiler analyzes components and generates fine-grained DOM update logic that runs at runtime.

No reconciliation. No component re-runs. Just surgical updates to exactly the nodes that changed.

The result is a framework that sits conceptually between Solid (fine-grained signals) and Svelte (compiler-driven output), but with TypeScript treated as a first-class citizen from the ground up — not bolted on after the fact.

How Ripple’s Fine-Grained Reactivity Works

Ripple’s fine-grained reactivity model centers on two primitives:

  • track() — creates a reactive value or derived computation
  • @ — the access operator for reading and writing tracked values
import { track } from 'ripple'

export component Counter() {
  let count = track(0)
  let double = track(() => @count * 2) // auto-derived, no dependency array

  <div>
    <p>{@count}</p>
    <p>{@double}</p>
    <button onClick={() => @count++}>{"Increment"}</button>
  </div>
}

When @count changes, only the DOM nodes that depend on it update. double recomputes automatically. There’s no useMemo, no dependency array, no stale closure to debug.

This differs meaningfully from React’s model, where state changes trigger full component re-execution, and from Solid’s createSignal, which Ripple intentionally avoids mimicking. The track() naming signals a different mental model: you’re declaring a tracked relationship, not wiring up a signal graph manually.

For reactive collections, Ripple introduces #[] (TrackedArray) and #{} (TrackedObject), which allow direct mutation:

const todos = #[]
todos.push({ id: 1, text: 'Write docs', completed: false }) // UI updates automatically

No spread operators. No setState. Just mutate and move on.

The Ripple TS Frontend Framework Developer Experience

Ripple ships with a focused but practical tooling story:

  • CLI scaffolding: npm create ripple my-app gets you a Vite-powered project in seconds
  • VSCode extension: IntelliSense, diagnostics, and error highlighting inside .ripple files
  • Prettier and ESLint support: Full formatting and linting for .ripple modules
  • Scoped styles: <style> blocks inside components are automatically scoped, no CSS Modules setup required

Components use a component keyword instead of function, and templates are statements rather than return values — a subtle shift that gives the compiler more room to optimize:

component Button(props: { text: string, onClick: () => void }) {
  <button onClick={props.onClick}>{props.text}</button>
}

Control flow uses plain JavaScript: for loops, if/else blocks, and try/catch for error boundaries — no .map() gymnastics or <Show> wrapper components required.

Regarding server-side rendering: Ripple’s documentation references render (server) and hydrate (client) APIs, so SSR is part of the design direction. The ecosystem around it is early and evolving, and this isn’t a framework you’d ship a production app with today.

Conclusion

Ripple is a genuine technical experiment from someone with rare framework pedigree. The core ideas — lazy reactive evaluation, compiler-owned dependency tracking, TypeScript-native syntax — are worth understanding even if you never write a line of Ripple code for production.

If you’re curious, the GitHub repo and documentation are the right starting points. Spin up the Vite starter, build a counter or a small form, and see whether the mental model clicks.

The interesting frameworks rarely announce themselves loudly. They just make you think differently about the ones you already use.

FAQs

React re-executes entire components on state changes and relies on hooks like useMemo for optimization. Solid uses fine-grained signals but requires manual signal creation. Ripple combines compiler-driven analysis with its track() primitive and @ operator to generate surgical DOM updates at build time, removing the need for dependency arrays or manual memoization entirely.

No. Ripple is an early-stage experimental framework. While its tooling includes Vite integration, a VSCode extension, and scoped styles, the ecosystem is still evolving. It is best suited for exploration and learning rather than shipping production applications at this point.

TrackedArray (#[]) and TrackedObject (#{}) are reactive collection primitives in Ripple. They let you mutate data directly using standard operations like push or property assignment, and the UI updates automatically. This eliminates the need for immutable update patterns, spread operators, or setState calls common in React.

Ripple's documentation references render and hydrate APIs, indicating that SSR is part of the framework's design direction. However, the SSR story is still early. There is no mature meta-framework or production-tested SSR pipeline comparable to Next.js or SvelteKit available for Ripple yet.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay