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

@avento-space/ts-ui

v1.1.1

Published

Framework-agnostic Web Components UI library with signals. Drop-in UI for React, Vue, Angular — zero adapters needed.

Readme

Avento TS UI

Framework-agnostic, signal-driven UI library for TypeScript.

Build reactive user interfaces once and render them anywhere — DOM, SSR, or custom targets — without coupling your components to any specific framework, browser API, or runtime environment.


Philosophy

Avento TS UI is built on a strict separation of concerns:

  • Core — abstract UI model (VNodes), reactive primitives (signals/computed/effects), context, store, lifecycle, and plugin system. Zero platform dependencies.
  • Render — generic Renderer<T, THost> interface that decouples UI definition from output strategy.
  • Adapters — platform-specific renderers (DOM with reconciliation and hydration, SSR with streaming).
  • Components — pure functional components consuming (props, children?) => VNode, fully portable across all adapters.

No layer depends on the internals of another. The same component function works unchanged in the browser and on the server.


Features

  • Signal-based reactivity — fine-grained, dependency-tracked, auto-batched updates
  • Computed values — lazy, cached, dependency-aware derived state
  • Pure functional components — no classes, no this, no hidden state
  • Pluggable renderers — DOM (with reconciliation + hydration), SSR (string + streaming)
  • Context system — typed provider chain for dependency injection
  • Immutable store — subscription-based state management built on signals
  • Lifecycle hooksonMount, onUnmount, onUpdate (enabled by renderer)
  • Plugin architecture — named hooks for extensibility (router, devtools, etc.)
  • Fragment support — group children without extra DOM nodes
  • JSX transformjsx/jsxs/jsxDEV functions for compiler integration
  • Strong TypeScript — full type inference for signals, components, and renderers
  • Zero runtime dependencies — only TypeScript

Quick Start

Install

npm install @avento/ts-ui

DOM Rendering

import { h, signal, computed, effect, mount } from '@avento/ts-ui';

const count = signal(0);
const doubled = computed(() => count.get() * 2);

function App() {
  return h('div', { class: 'app' }, [
    h('h1', null, ['Avento Counter']),
    h('p', null, [`Count: `, count]),
    h('p', null, [`Doubled: `, doubled]),
    h('button', { onClick: () => count.set(count.get() + 1) }, ['+']),
    h('button', { onClick: () => count.set(count.get() - 1) }, ['-']),
  ]);
}

const renderer = mount(h(App), document.getElementById('root')!);

Signal values passed directly in children or props are automatically bound — the DOM updates reactively without re-rendering the entire tree.

SSR Rendering

import { h, renderToString } from '@avento/ts-ui';

function Page() {
  return h('div', { class: 'page' }, [
    h('h1', null, ['Hello from SSR']),
    h('p', null, ['This was rendered on the server.']),
  ]);
}

const html = renderToString(h(Page));
console.log(html);
// <div class="page"><h1>Hello from SSR</h1><p>This was rendered on the server.</p></div>

Architecture

src/
├── core/           # VNode, Signal, Component, Context, Store, Lifecycle, Plugin
├── render/         # Renderer<TOutput,THost> interface + VNode resolver
├── adapters/       # Platform renderers
├── adapters/       # Platform renderers
│   ├── dom/        #   mount(), hydrate(), signal DOM bindings
│   └── ssr/        #   renderToString(), renderToStream()
├── components/     # Reusable components (Button, Input, List, Portal)
├── plugins/        # Router plugin + plugin types
├── compiler/       # JSX transform (jsx/jsxs/jsxDEV)
└── devtools/       # VNode inspector, state logger

Dependency Flow

Components  ──►  Core  ◄──  Plugins
                    │
              Render Interface
                    │
          ┌──────────┼──────────┐
          │          │          │
        DOM        SSR      Custom Adapter

Core never imports from adapters. Adapters import Core. Components import only Core types and the h factory.


Core Concepts

VNode

The universal UI representation:

interface VNode {
  type: string | Component | typeof Fragment;
  props: Record<string, any> | null;
  children: VNodeChild[];
  key?: string | number;
}

h() — Hyperscript

h('div', { class: 'container' }, [
  h('h1', null, ['Title']),
  h('p', null, ['Paragraph with ', signalValue]),
]);
  • type — element tag name, component function, or Fragment
  • props — attributes, properties, event listeners (onClick, etc.), signals
  • children — VNodes, strings, numbers, booleans, null, or signals

Signals

import { signal, computed, effect, batch, untrack } from '@avento/ts-ui';

const name = signal('World');
const greeting = computed(() => `Hello, ${name.get()}!`);

effect(() => {
  console.log(greeting.get()); // logs whenever name changes
});

batch(() => {
  name.set('Agnostic');
  name.set('UI'); // only one notification after batch
});

Context

import { createContext, useContext, h, mount } from '@avento/ts-ui';

const Theme = createContext('light');

function Panel() {
  const theme = useContext(Theme);
  return h('div', { class: `theme-${theme}` }, ['Themed content']);
}

Browser DOM

import { mount } from '@avento/ts-ui';

const instance = mount(h(App), document.getElementById('root')!);
// instance.render(newVNode) — re-render
// instance.hydrate(vnode)   — attach to existing DOM
// instance.destroy()        — unmount and clean up

Signal values in props or children create direct DOM bindings — only the affected nodes update when the signal changes.


Server-Side Rendering

import { renderToString, renderToStream } from '@avento/ts-ui';

// Full document
const html = renderToString(h(Page));

// Streaming
for await (const chunk of renderToStream(h(Page))) {
  res.write(chunk);
}

Signals are resolved at render time via untrack(). Event handlers and other DOM-only props are omitted from the HTML output.


Built-in Components

Avento TS UI provides a set of highly optimized, platform-agnostic UI components:

  • Button: Custom styled interactive button.
  • Input: Reactive text input control with controlled states.
  • List: Keyed child element list wrapper.
  • VirtualList: Zero-overhead windowed list virtualization (scrolling requires external scroll bindings).
  • Portal: Renders children outside the standard DOM hierarchy.

For complete API details and scroll state implementation examples, see the Components Documentation.


Plugins

import { registerPlugin, createRouter } from '@avento/ts-ui';

const router = createRouter({ mode: 'history' });
registerPlugin(router);

router.navigate('/dashboard');

The plugin system uses named hooks. Custom plugins receive a PluginAPI to register and invoke hooks.


JSX Support

Configure your TypeScript tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@avento/ts-ui"
  }
}

The compiler module exports jsx, jsxs, and jsxDEV for the automatic JSX runtime.


Project Structure

| Layer | Directory | Responsibility | |-------|-----------|----------------| | Core | src/core/ | VNode, signals, context, store, lifecycle, plugins | | Render | src/render/ | Renderer interface, VNode resolver | | DOM Adapter | src/adapters/dom/ | mount(), hydrate(), signal bindings | | SSR Adapter | src/adapters/ssr/ | renderToString(), renderToStream() | | Components | src/components/ | Button, Input, List, Portal | | Plugins | src/plugins/ | Router plugin | | Compiler | src/compiler/ | JSX transform functions | | DevTools | src/devtools/ | Inspector, state logger |


License

MIT