npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mjbeswick/reactive-dom

v2.0.1

Published

A React-like library with reactive signals and computed values

Downloads

4

Readme

⚡ Reactive-DOM

A React-like library with reactive signals and computed values for building dynamic web applications

⚠️ Proof of Concept Warning ⚠️

This project is currently a proof of concept and is not suitable for production use. It's designed to explore reactive programming patterns and demonstrate an alternative approach to React. Use at your own risk!

NPM Version License TypeScript Build Status

📋 Table of Contents

✨ Features

  • ⚡ Reactive Signals: Create reactive state that automatically updates when dependencies change
  • 🧮 Computed Values: Derive values from signals with automatic dependency tracking
  • 🌍 Global State Management: Create global state anywhere without providers, context, or complex setup
  • 🚫 No Virtual DOM: Direct DOM updates without the overhead of virtual DOM reconciliation
  • 🧩 Component Pattern: Build components using a familiar JSX-like syntax
  • 🎯 Event Handling: Built-in support for DOM events
  • 🔒 TypeScript Support: Full TypeScript support with type safety
  • 🎨 CSS Modules: Scoped styling with theme support
  • 🌓 Theme System: Light, dark, and high-contrast themes
  • 🧹 Automatic Cleanup: Prevents memory leaks with smart cleanup
  • 📦 Zero Dependencies: Lightweight with no external dependencies
  • ⚡ Optimized Bundles: Multiple formats (ESM, UMD, CJS) with Rollup
  • 🎯 Tree-shaking: Individual modules for optimal bundling

🚀 Why Reactive-DOM?

Signals vs React Hooks

Signals are fundamentally better than React hooks because:

  • 🎯 Granular Updates: Signals update only the specific DOM elements that depend on them, not entire components
  • ⚡ No Re-renders: Unlike React's component re-rendering, signals update the DOM directly without virtual DOM overhead
  • 🧠 Automatic Dependency Tracking: Signals automatically track dependencies without manual dependency arrays
  • 🔧 Simpler Mental Model: No need to understand hooks rules, dependency arrays, or component lifecycle
  • 🚫 No useEffect: No need for useEffect which creates unnecessary complexity and side effect management
  • 📦 Smaller Bundle: No virtual DOM, reconciliation, or complex state management overhead
  • 🎨 Better Performance: Direct DOM updates are faster than React's render cycle
  • 🌍 Global State Without Providers: Create global state anywhere without complex provider patterns or context setup

Pure TypeScript vs JSX

Pure TypeScript is better than JSX because:

  • 🔒 Type Safety: Full TypeScript support with compile-time type checking
  • 🧹 No Build Step: No need for JSX transformation or Babel configuration
  • 📦 Smaller Bundle: No JSX runtime or transformation overhead
  • 🎯 Better IDE Support: Full IntelliSense, autocomplete, and refactoring support
  • 🔧 Simpler Tooling: No need for JSX plugins, Babel, or special build configurations
  • 📚 Familiar Syntax: Uses standard JavaScript/TypeScript function calls
  • 🎨 More Flexible: Easier to compose, transform, and manipulate programmatically
  • ✍️ Less Code: More concise and easier to write without verbose JSX syntax
  • 🚫 No XML Recreation: JSX is just trying to recreate XML in TypeScript, which has no advantages aside from looking like HTML, but is less efficient

📦 Installation

npm install reactive-dom

🚀 Quick Start

Ready to build reactive apps without the React complexity? Let's dive in! 🏊‍♂️

import { signal, computed, div, h1, p, button, render } from 'reactive-dom';

// Create global reactive signals - accessible anywhere in your app
const count = signal(0);
const user = signal({ name: 'John', email: '[email protected]' });

// Create a component
const Counter = () => {
  // Create a local computed value
  const doubleCount = computed(() => count.get() * 2);

  // Create a reactive element
  return div(
    { className: 'counter' },
    h1('Counter Example'),
    p('Count: ', count),
    p('Double Count: ', doubleCount),
    p('User: ', user.get().name),
    button(
      {
        onClick: () => count.set(count.get() + 1),
      },
      'Increment',
    ),
  );
};

// Another component can access the same global state
const UserProfile = () => {
  return div(
    { className: 'profile' },
    h1('User Profile'),
    p('Name: ', user.get().name),
    p('Email: ', user.get().email),
  );
};

// Render to DOM
render(Counter(), document.getElementById('app'));

🛠️ Development

For development setup, building, testing, and project structure, see DEVELOPMENT.md.

📚 API Reference

For detailed API documentation, see API.md.

Core Functions

signal<T>(initialValue: T): Signal<T>

Creates a reactive signal with an initial value.

const count = signal(0);
count.set(5); // Update value
console.log(count.get()); // Get current value

computed<T>(fn: () => T): Computed<T>

Creates a computed value that automatically updates when dependencies change.

const doubleCount = computed(() => count.get() * 2);

render(element: HTMLElement, container: HTMLElement): void

Renders a reactive element into a DOM container.

render(Counter(), document.getElementById('app'));

DOM Elements

All HTML elements are available as factory functions:

import { div, h1, p, button, input, span } from 'reactive-dom';

const element = div(
  { className: 'container' },
  h1({ children: 'Hello World' }),
  p({ children: 'This is a paragraph' }),
  button({ onClick: handleClick, children: 'Click me' }),
);

🎯 Examples

The examples/ directory contains comprehensive examples demonstrating Reactive DOM features:

Available Examples

  • 🔢 Counter (/counter): Basic reactive state management with increment/decrement buttons
  • 🎲 Random Generator (/random-generator): Signal updates with automatic UI re-rendering
  • 🐛 Debug (/debug): Reactive signals with disabled states and real-time logging
  • 🌐 Router (/router): Advanced client-side routing with navigation and error handling
  • 🔒 Strongly Typed Props (/strongly-typed-props): Demonstrates TypeScript type safety for all HTML element props

Example Features

Each example demonstrates different aspects of Reactive DOM:

  • Reactive Signals: Global state management without providers or context
  • Computed Values: Automatic dependency tracking and derived state
  • Event Handling: Built-in DOM event support with reactive updates
  • CSS Modules: Scoped styling with theme support
  • Type Safety: Full TypeScript support with strongly typed props
  • Routing: Client-side routing with dynamic route handling
  • Error Boundaries: Graceful error handling and recovery

Running Examples

# Run all examples simultaneously
./examples/run-all.sh

# Or run individual examples
cd examples/counter && npm install && npm run dev
cd examples/router && npm install && npm run dev
cd examples/strongly-typed-props && npm install && npm run dev

Example Ports

Each example runs on a different port:

  • Counter: http://localhost:5173
  • Debug: http://localhost:5174
  • Random Generator: http://localhost:5175
  • Router: http://localhost:5176
  • Strongly Typed Props: http://localhost:3000

For detailed information about each example, see the Examples README.

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.