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

@angerenage/jtx

v1.1.1

Published

Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.

Readme

JTX — Add interactivity to HTML, no framework required

JTX is a tiny library that makes a server‑rendered page feel alive. Keep writing normal HTML on the server; sprinkle a few small tags and attributes in your markup; JTX binds your JSON data to the page so it updates reactively — without a build step or a virtual DOM.

For the full, precise specification, see SPEC.md. This README is a practical "how to".

What JTX is

  • A lightweight layer on top of your existing HTML.
  • Driven by JSON from HTTP/SSE/WebSocket sources or local state.
  • Declarative: add attributes/tags; JTX updates the DOM for you.
  • Build‑free: include a script and you’re done.

Why use it

  • Keep SSR and progressively enhance with minimal client code.
  • Great for lists, text, toggles, and live feeds.
  • Stays close to the platform — just HTML + a few helpers.

Quick Start

  • NPM: npm install @angerenage/jtx
  • CDN: <script src="https://unpkg.com/@angerenage/jtx"></script>

JTX auto‑initializes on DOMContentLoaded. If you append HTML later, call JTX.init(subtreeElement).

Core Concepts

  • @name.path: read values from a state or source.
  • Expressions are plain JS (in attribute values).
  • Event handlers use jtx-on="event: code".

Helpers available in expressions and handlers:

  • emit(name, detail): dispatch a custom event on the current element.
  • refresh('srcName') or @src.refresh(): re‑fetch a source.
  • get/post/put/patch/del(url, [bodyOrHeaders], [headers]): thin fetch helpers.
  • $event: current event in jtx-on.
  • $el: current element.

jtx‑state — Local, Mutable State

Declare a state and expose keys as data to descendants.

<jtx-state name="ui" counter="0" theme="'light'" persist="theme" persist-url="counter">
  <button jtx-on="click: @ui.counter++">+</button>
  <span jtx-text="@ui.counter"></span>
</jtx-state>
  • name (required): unique id.
  • Any other attribute becomes a key (evaluated once at init).
  • persist: comma‑separated keys saved to localStorage.
  • persist-url: comma‑separated keys synced to query string.

Events you can listen to (they bubble):

  • init: { name, value } when created.
  • update: { name, keys, value } after batched changes.

Two‑way binding with form elements via jtx-model:

<jtx-state name="form" email="''">
  <input type="email" jtx-model="@form.email">
  <p jtx-text="@form.email"></p>
</jtx-state>

Notes:

  • States are scoped: a <jtx-state> inside a template/section shadows outer states of the same name.

jtx‑src — Remote or Streaming Data

Fetch JSON over HTTP or stream JSON via SSE/WebSocket. Use child content to render the value.

<!-- HTTP example: fetch on load and every 30s -->
<jtx-src name="orders" url="/api/orders" fetch="onload, every 30s" select="items">
  <jtx-loading>Loading…</jtx-loading>
  <jtx-error>Could not load orders.</jtx-error>
  <jtx-empty>No orders yet.</jtx-empty>

  <ul>
    <jtx-insert for="o in @orders">
      <jtx-template>
        <li>
          <span jtx-text="o.id"></span> — <span jtx-text="o.title"></span>
        </li>
      </jtx-template>
    </jtx-insert>
  </ul>
</jtx-src>
<!-- SSE example: stream events; optionally filter with sse-event -->
<jtx-src name="feed" url="sse:/events" sse-event="tick">
  <p jtx-text="@feed.$status"></p>
</jtx-src>

<!-- WebSocket example -->
<jtx-src name="chat" url="wss:/ws/chat"></jtx-src>

Attributes:

  • name (required): unique id.
  • url (required): HTTP (/api or https://…), SSE (sse:/path), WS (ws:/… or wss:/…).
  • fetch: when to fetch (HTTP only): onload (default), idle, visible, every 5s, or manual for manual control.
  • headers: JSON or expression for request headers, e.g. { Authorization: 'Bearer ' + @auth.token }.
  • select: dot‑path to pick a nested value from the JSON payload.
  • sse-event: for SSE, only handle a specific event type.

Children you can add inside a jtx-src (optional): jtx-loading, jtx-error, jtx-empty.

Programmatic refresh:

  • In JS: JTX.refresh('orders')
  • In expressions/handlers: @orders.refresh() or refresh('orders')

Source status and error are readable in expressions:

  • @orders.$status is one of idle | loading | ready | error
  • @orders.$error contains last error, if any

Events you can listen to on the <jtx-src> element:

  • init: { name } when registered.
  • fetch: { url, headers } before an HTTP request.
  • update: { name, value } after new data is set.
  • error: { name, type, status?, message, raw? } on network/parse/connection errors.
  • open: { name, type: 'sse' | 'ws' } when a stream opens.
  • close: { name, code?, reason? } when a stream closes.
  • message: { name, type, data, lastEventId? } for raw SSE/WS messages. For SSE events, JTX also dispatches a DOM event named after it's type on the <jtx-src> in addition to message.

Rendering Helpers (Attributes)

Use these attributes anywhere in your HTML:

  • jtx-if="expr": add/remove the element based on truthiness.
  • jtx-show="expr": toggle hidden attribute.
  • jtx-text="expr": set textContent (falls back to original content if null/undefined).
  • jtx-html="expr": set innerHTML (you are responsible for sanitizing).
  • jtx-attr-FOO="expr": bind any attribute FOO (boolean true => present, false/null/undefined => removed).
  • jtx-model="@state.key": two‑way bind form inputs/selects/textarea to state (supports nested paths like @state.user.name).
  • jtx-on="event: code; other: code": run JS on events. Also supports timers: every 5s: code.

Lists and Templates — <jtx-insert>

Insert text/HTML or render lists with a template.

Scalar insert:

Hello, <jtx-insert text="@user.name">guest</jtx-insert>!

List insert:

<jtx-insert for="item in @orders" key="item.id" strategy="replace">
  <jtx-template>
    <div>
      <span jtx-text="item.id"></span>
      <span jtx-text="item.title"></span>
    </div>
  </jtx-template>
</jtx-insert>

Options:

  • for (required for lists): item in <expr> or value,key in <expr>.
  • key: stable key per item (recommended; required to accumulate with merge).
  • strategy:
    • replace (default): remove all current items and insert the new ones from scratch.
    • append: always add the received item(s) to the end.
    • prepend: always add the received item(s) to the beginning.
    • append merge: keyed upsert — update existing items by key; append new keys; respects window (trims from start).
    • prepend merge: keyed upsert — update existing items by key; prepend new keys; respects window (trims from end).
  • window: required for merge strategies and optional for append/prepend — caps the number of rendered items.
  • Optional children: jtx-loading, jtx-error, jtx-empty (useful when nested under a jtx-src).

Initialization Hooks

  • Auto‑init on page load. To initialize a dynamically inserted subtree: JTX.init(element).
  • Attributes inside <jtx-template> are compiled per item when the list renders.

Tips

  • Keep expressions simple and safe; they run in the browser.
  • Prefer select on jtx-src to avoid repeating deep paths in templates.
  • Unknown @name references warn in the console; check your name attributes.

Learn More

  • Detailed behavior, edge cases, and full semantics: see SPEC.md.

License

MIT — see LICENSE.