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

@expressive/dom

v0.6.0

Published

MVC-native DOM renderer.

Readme


@expressive/dom renders Expressive MVC without React or Preact. Function components are renderer-stateless: they project props and MVC snapshots into DOM, while Model.get() supplies dependency tracking. Owned state lives on classes - a Component field or <Component for>.

npm install @expressive/mvc @expressive/dom
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@expressive/dom"
  }
}
import { Model, Component } from '@expressive/mvc';
import { render } from '@expressive/dom';

class Counter extends Model {
  count = 0;
  increment() {
    this.count++;
  }
}

function Count() {
  const { count, increment } = Counter.get();
  return <button onClick={increment}>{count}</button>;
}

const unmount = render(
  <Component for={Counter}><Count /></Component>,
  document.getElementById('app')!
);

style recursively composes conditional class tokens and inline declarations. Strings become classes; objects merge left-to-right and render inline. Use className for a browser-specific class outside the composition. The class attribute spelling and CSS declaration strings are not supported.

<button
  className="external-widget"
  style={[styles.button, active && 'active', { width }]}
/>

style on a component automatically reaches its rendered host root, including through component, fragment, provider, portal, and collection boundaries. A fragment applies it to each host root. Forwarded style overrides the root's own, with the outermost caller winning. A component which reads its style prop while rendering owns placement, and nothing is forwarded. It receives a frozen object of the caller's inline declarations - spread, pluck or merge it freely; the caller's classes travel hidden with it. className applies to elements only.

A component may register immutable maps with style(Component, map). A _name entry is a rule, applied by a truthy _name attribute or a matching host tag and emitted as one class named after its source; nested inside a rule it opens a descendant scope. Component names never match - they do not survive minification. Bare keys are declarations, or macro calls where a macro owns the name, and those at the top of a map form a base rule applied to each of the component's host roots. Macros are defined only by macro() - within a map, call a plain function instead. $name is reserved. _ attributes never reach the DOM, and 0 or '' leaves a rule off. A map never reaches inside a child component; only the class chain inherits.

function Button({ active }: { active: boolean }) {
  return <button _active={active}>Save</button>;
}

style(Button, {
  padding: '8px',
  _active: { fontWeight: 700 }
});

Global maps use macro(map) and can live in side-effect imports. Register macros and styles before the first relevant render. A key resolves at its topmost definition; a macro returning its own name falls to the next definition down, then through any '*' handler. Unhandled keys reach the host, which joins arrays and rejects functions and objects - units belong to a macro, never a guess.

Inline style always beats classes; among classes, a caller's rule beats the callee's, and a rule carried through more component style props wins - independent of render order. false, null, and undefined omit an entry; 0 remains a macro argument.

Component retains the React adapter's semantics: fields read by render() are dependencies, owned instances mount and clean up with the DOM range, and an externally activated instance can be placed directly without transferring ownership.

The first release includes keyed reconciliation, native events, refs, SVG, <Component for> providers, direct has / map collection rendering, portals, lazy components, error and suspense fallbacks, generated component appearance rules, and retention of committed content while pending() work suspends. It deliberately excludes standalone hooks, synthetic events, memo wrappers, SSR, hydration, and build-time style extraction.

See the DOM renderer guide for the API and constraints. This package currently targets browser DOM; native rendering and build-time expressive-jsx extraction are not included.

License

MIT